Goal is a toolkit for high productivity web development in Go language in the spirit of Revel Framework that is built around the concept of code generation.

Goal

Goal is a set of tools for high productivity web development in Go language.

Goal, being mostly inspired by Revel Framework and its discussions, is built around the concept of controllers and actions. However, as opposed to Revel and other high level frameworks Goal does not use runtime reflection and does not require your app to import monolithic dependencies.

Instead Goal is implemented in a form of independent tools that may be used with go generate. That allows us to achieve type safety, minimalism of dependencies, compatability with the standard library, and productivity for the end-developers. At the same time Goal is very customizable (you can bring your own router, template system, and any other component). But that's without prejudice to the easiness and seamless of experience thanks to good defaults.

Getting Started

  1. Install Goal:

     go get -u github.com/goaltools/goal
    
  2. Create a new skeleton application:

     goal new github.com/$username/$project
    
  3. Start a watcher / task runner:

     goal run github.com/$username/$project
    

Documentation

All goal generate * tools may be used with go generate.

Status

Proof of Concept: not ready for use in the wild. Working on: splitting the project into independent repos.

GoDoc Build Status Coverage Status Go Report Card

License

Distributed under the BSD 2-clause "Simplified" License unless otherwise noted.

Comments
  • handlers folders disappear?

    handlers folders disappear?

    When i execute "goal new mygoal" , it is ok.

    But when i execute "goal run mygoal", in the "mygoal/assets", the "handlers" subdirectory and its files are disappeared? before it, the handlers subdirecory and its files are exists!
    My "$GOPATH/src" is ok! so the errors are the following: ``

     Running `goal generate handlers --input ./controllers/ --output ./assets/handlers/`...
    
    Removing "./assets/handlers/" directory if already exists...
    
    Error: path "F:\golang/src/mygoal\controllers" is not inside "$GOPATH/src".
    
    Failed to run a command "go build -o ./bin/run.exe mygoal", error: exit status 1
    
    Preparing "./bin/run.exe"...
    
    Starting a new instance of `./bin/run.exe`...
    
    Adding "./views/" to the list of watched directories...
    
    Failed to start a command `./bin/run.exe`, error: exec: "./bin/run.exe": file does not exist.
    

    `` where is the "run.exe"? what's wrong with it?

  • How to get the controller's name and action?

    How to get the controller's name and action?

    How to get the controller's name and action? How to get all the names and actions but "Before,After,Initially,Finnally" I want to intercept some actions for authority.

  • Document every tool

    Document every tool

    Manual lives here. The docs are for MVP but they are still valid. Every tool here must have their own README.md as follows:

    • tools/
      • run/
        • main.go
        • ...
        • README.md
      • new/
        • main.go
        • ...
        • README.md
      • ...

    And we can have a list and short descriptions of all supported tools in the root README.md.

  • Moving project to its own organization: a new name is needed

    Moving project to its own organization: a new name is needed

    It is both possible to:

    • Come up with the idea of an organization name but use the same toolkit name;
    • Rename the toolkit, too.

    My proposals are:

    • goaltools/goal (goaltools.com domain is available)
    • goalproject/goal (.com, .org, .net domains are taken)
    • ~~goaltech/goal (both GH username goaltech and domains are taken)~~
    • Rename back to sunplate (we have sunplate.club domain)

    Other options are welcome.

  • Routes generation

    Routes generation

    Routes in Goal

    Goal's routes package in the auto generated skeleton app is nothing more than a global List variable and calls to the default router:

    var List = r.Routes{
        r.Get("/some/path", h.SomeController.SomeAction),
        r.Post(...),
        ...
    }
    
    • Advantages of this approach are:
      1. Router of end-developer's choice, nothing Goal specific.
      2. User can modify routes package and write there whatever code he/she needs.
      3. Type safe (e.g. r.Get will be compiled, r.Gte wont be; h.Controller.Action will, h.Controller.Atcion wont, etc).
    • Disadvantages:
      1. End-developer has to switch between controller file and routes. You're adding a new action, then have to open routes.go to reflect that addition.
      2. We need to implement reverse routes generation (read more about reverse routes in Revel). That means our parser will have to know how to handle the routes.go (so we'll have to introduce Goal specific code or convention).

    Proposal

    Use annotation like syntax. E.g. in Bottle.py there is:

    @route('/hello/<name>')
    def greet(name):
        return template('<b>Hello {{name}}</b>!', name=name)
    

    There are no annotations in Go, but other tools such as go generate and go build use tags in comments. That's what we can do, too:

    //@get /hello/:name
    func (c App) Greet(name string) http.Handler {
        c.Context = name
        return c.Render()
    }
    

    Import of actions

    Controllers end-developer embeds may include actions with routes. Those can be prefixed as follows:

    type App struct {
        // ControllerWithErrorMsgActions contains Error404 action
        // with "@get /404".
        pkg.ControllerWithErrorMsgActions `@route:"/errors/"`
    }
    
    //
    // The code above is equivalent to writing right in this file:
    //
    
    //@get /errors/404
    func (c *App) Error404() http.Handler {
        ... // Whatever Error404 of ControllerWithErrorMsgActions controller does.
    }
    

    Result of generation

    It is supposed the generated code will be similar to:

    var Routes = []struct{
        Type, Pattern string
        Handler http.Handler
    }{
        {Type: "GET", Pattern: "/hello/:name", Handler: h.App.Greet}
        ...
    }
    

    This Routes then can be used by the router (after importing the package where it's located).

    For now the variable should be located within generated handlers package (as it is easy to implement). After MVP version will require generation of a new routes package in ./assets/.

    Reverse routing

    We'll use controllers to generate both routes and reverse routes. A new issue must be open for the latter.

  • Static file default paths

    Static file default paths

    The default path for static files are at example.com/static/styles/app.css. Maybe it should be at root directory example.com/styles/app.css.

    If someone adds a robots.txt file in the static folder it would be at example.com/static/robots.txt. I read that the robots.txt file should be at root example.com/robots.txt

    I also think it would be nice to follow twitter bootstrap and html5 boilerplate naming of javascript and css folders. They use /css/main.css and /js/main.js

  • A new format of task runner's configuration file

    A new format of task runner's configuration file

    Goal's run tool uses YAML for its configuration file. The file is described here. However, I'd like to replace it by something else. I want all code including dependencies to meet the following requirements (apart from the general quality of the library):

    1. gofmt-ed with -s flag;
    2. golint-ed
    3. checked with go vet. go-yaml doesn't meet those requirements and that is the only Go implementation of YAML that is active and maintained.

    I have played with different formats. Not sure about XML. But JSON doesn't work, comments are not supported and the whole config looks very difficult to read and understand with all those ", ,, and {} that could be omitted. It is also possible to use a custom format. Here is one I have developed right for this use-case.

  • Multi-domain / Sub-domains?

    Multi-domain / Sub-domains?

    In httprouter, it supportes Multi-domain / Sub-domains? https://github.com/julienschmidt/httprouter#web-frameworks-based-on-httprouter Could goal support it?

  • Define high level goals

    Define high level goals

    Let's define the high level goals of the project. What are we trying to achieve? What are the priorities?

    Can it be more than a traditional (by traditional I mean HTML template system as V) MVC framework? Probably, like Meteor, Volt, Webalchemy. Should it? Or we can just make sure it works good with Angular, React, and whatever is fashionable now.

    The code generation we are relying on is pretty powerful and we can do a lot of cool things. We just need to decide what cool things we want.

    And to the question of positioning: is it a framework or toolkit? It is implemented in a form of separate tools. Every one is independent and can be used on its own. But on the other hand all of the tools play nicely with each other and form a single framework. So, how should we call it (need to know as it is used a lot in the comments and docs)? I have started with "toolkit" but recently switched to "framework".

  • fix new Controller instance is failed

    fix new Controller instance is failed

    old code is

    func (t tControllers) newC(w http.ResponseWriter, r *http.Request, ctr, act string) *contr.Controllers {
        // Allocate a new controller. Set values of special fields, if necessary.
        c := &contr.Controllers{}
    
        // Allocate its parents. Make sure controller of every type
        // is allocated just once, then reused.
        c.Templates = c.Errors.Templates
        c.Errors = &c5.Errors{}
        c.Static = &c3.Static{}
        c.Sessions = &c2.Sessions{
    
            Request: r,
    
            Response: w,
        }
        c.Requests = &c1.Requests{
    
            Request: r,
    
            Response: w,
        }
        c.Global = &c0.Global{
    
            CurrentAction: act,
    
            CurrentController: ctr,
        }
        c.Errors.Templates = &c4.Templates{}
        c.Errors.Templates.Requests = c.Requests
        c.Errors.Templates.Global = c.Global
        c.Templates.Requests = c.Requests
        c.Templates.Global = c.Global
    
        return c
    }
    

    new code is

    
    func (t tControllers) newC(w http.ResponseWriter, r *http.Request, ctr, act string) *contr.Controllers {
        // Allocate a new controller. Set values of special fields, if necessary.
        c := &contr.Controllers{}
    
        // Allocate its parents. Make sure controller of every type
        // is allocated just once, then reused.
        c.Templates = &c4.Templates{}
        c.Errors = &c5.Errors{}
        c.Static = &c3.Static{}
        c.Sessions = &c2.Sessions{
    
            Request: r,
    
            Response: w,
        }
        c.Requests = &c1.Requests{
    
            Request: r,
    
            Response: w,
        }
        c.Global = &c0.Global{
    
            CurrentAction: act,
    
            CurrentController: ctr,
        }
        c.Errors.Templates = c.Templates
        c.Templates.Requests = c.Requests
        c.Templates.Global = c.Global
    
        return c
    }
    
  • Fix tests of generate/handlers tool

    Fix tests of generate/handlers tool

    internal/reflect returns functions/methods in a random order that's why tests of tools/generate/handlers fail randomly (in 50% of cases restart of tests is necessary). Make sure the issue is resolved when start working on #3.

  • Allocate parent controllers just once

    Allocate parent controllers just once

    Intro

    There is a controller with its special action:

    type GrandParent struct {
        Context map[string]interface{}
    }
    
    func (c *GrandParent) Before() http.Handler {
        println("This is GrandParent")
        c.Context = map[string]interface{}{}
    }
    

    The controller above is embedded by a number of other controllers.

    type Parent1 struct {
        *GrandParent
    }
    type Parent2 struct {
        *GrandParent
    }
    

    Those controllers are embedded by our main controller.

    type Child struct {
        *Parent1
        *Parent2
    }
    
    func (c *Child) Index() http.Handler {
    }
    

    Problem

    The problem is the GrandParent controller will be allocated twice, meaning c.Parent1.GrandParent != c.Parent2.GrandParent. The output of the GrandParent's Before will be:

    This is GrandParent
    This is GrandParent
    

    As a result, we cannot share a context between controllers of different levels of embedding.

    Use-case

    This is the problem I've faced trying to implement #39. There is controllers/errors controller that is responsible for rendering error pages. We embed it in our main controller and mount its actions to * /errors:

    type Controllers struct {
        errors.Errors `@route:"/errors"`
    }
    

    Now if we want to pass some value to the actions of that Errors controller it doesn't work:

    func (c *Controllers) Before() http.Handler {
        c.Context["someKey"] = "someValue"
    }
    

    Because, Context of Controllers and Context of Errors are different instances. But they must be pointers to the same object.

    Expectations

    A single allocation per object per request. Special (Before and After) actions must be called just once: Parents must have priority over their Children.

  • Split `generate handlers` into multiple tools

    Split `generate handlers` into multiple tools

    Tool generate handlers is getting too complex. It should be split into multiple ones:

    • scan controllers (name TBD) - parses controllers and dependencies, serializes result and saves it as .json (or some other format that is TBD).
    • generate handlers - reads generated .json and creates a handlers package.
    • generate routes - reads generated .json and creates routes package.
    • generate reverse routes - reads generated .json and creates routes/reverse package.
  • Add some more functions?

    Add some more functions?

    1.When visit the static page ,such as http://localhost:8080/static/index.html,It still execute the Controller's All Initially() and Before() function? if visit the static page ,it will execute these function many time,because the index.htm include some css and js and jpg? Maybe another usage is that we can intercept the static file. Maybe should make a switch for it?

    the route for static is: r.Get("/static/*filepath", http.StripPrefix("/static/", http.FileServer(http.Dir("./static")), ).ServeHTTP),

    2.There are still not RenderXML and RenderFile methods.

    3.Have a flash function like revel's flash function? and the compressionTypes,cache.....?

    4.https? http2?

  • Wiki on web development in Go language

    Wiki on web development in Go language

    We need to work on the quality of our docs:

    • [ ] Better layout and navigation
    • [ ] Update things that are not up-to-date
    • [ ] Cover things that are missing (e.g. default controllers, goal new listing, etc.)

    Moreover, I propose to change the target audience we are trying to address. Not the Go web developers but those who have no experience with Go language and/or Web Development at all. The former is a pretty small group with already shaped preferences and tastes. We can attract fresh blood instead: people from other stacks and backgrounds.

    What we need:

    • [ ] More general purpose articles. E.g. about installation of Go and configuration of GOPATH with screenshots (on Linux / Windows / MacOS) and all
    • [ ] Screencasts
    • [ ] Better quality of content, more details, do not assume user is an expert
    • [ ] Tutorials
  • Feature: autoform

    Feature: autoform

    Creation and validation of forms is IMO the most boring part of web-development. Let's make it fun again. The use-case is:

    1. End-developer describes their data once.
    2. Goal toolkit generates the code that can be used for both form generation and its validation.

    We could possibly use struct tags for that. E.g.:

    type User struct {
        Name        string `autoform:"required=true,minsize=2,maxsize=100"`
        Email       string `autoform:"email=true"`
        Age         int    `autoform:"min=13,max=150"`
        CountryCode string `autoform:"length=2"`
        CardNumber  string
    }
    

    Though this is not type safe. Alternatively, we can apply a "magic methods" approach we use for the controllers.

    Related functionality in other frameworks

    1. https://docs.djangoproject.com/en/1.7/topics/forms/modelforms/
    2. https://www.playframework.com/documentation/2.1.0/JavaForms
  • Docker support

    Docker support

    Goal gives a error while trying to build a docker image with this dockerfile. It works if the project files are on a public github repo.

    fatal: could not read Username for 'https://github.com': No such device or address package github.com/davidhunter/goal-sample/server: exit status 128

    FROM golang:onbuild
    EXPOSE 8080
    

    Then their is another issue where I can't connect to it outside a container.

Related tags
go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.
go-zero is a web and rpc framework written in Go. It's born to ensure the stability of the busy sites with resilient design. Builtin goctl greatly improves the development productivity.

go-zero English | 简体中文 0. what is go-zero go-zero is a web and rpc framework that with lots of engineering practices builtin. It’s born to ensure the

Jan 2, 2023
laravel for golang,goal,fullstack framework,api framework
laravel for golang,goal,fullstack framework,api framework

laravel for golang,goal,fullstack framework,api framework

Feb 24, 2022
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch
Roche is a Code Generator and Web Framework, makes web development super concise with Go, CleanArch

It is still under development, so please do not use it. We plan to release v.1.0.0 in the summer. roche is a web framework optimized for microservice

Sep 19, 2022
Microservice framework following best cloud practices with a focus on productivity.

patron Patron is a framework for creating microservices, originally created by Sotiris Mantzaris (https://github.com/mantzas). This fork is maintained

Dec 22, 2022
beego is an open-source, high-performance web framework for the Go programming language.
beego is an open-source, high-performance web framework for the Go programming language.

Beego Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services. It is inspired by To

Jan 1, 2023
beego is an open-source, high-performance web framework for the Go programming language.
beego is an open-source, high-performance web framework for the Go programming language.

Beego Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services. It is inspired by To

Jan 8, 2023
letgo is an open-source, high-performance web framework for the Go programming language.

high-performance Lightweight web framework for the Go programming language. golang web framework,高可用golang web框架,go语言 web框架 ,go web

Sep 23, 2022
A web app built using Go Buffalo web framework

Welcome to Buffalo Thank you for choosing Buffalo for your web development needs. Database Setup It looks like you chose to set up your application us

Feb 7, 2022
GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.

GoFrame English | 简体中文 GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang. If you're a

Jan 2, 2023
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Jan 5, 2023
Golanger Web Framework is a lightweight framework for writing web applications in Go.

/* Copyright 2013 Golanger.com. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except

Nov 14, 2022
The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework.

jin About The jin is a simplified version of the gin web framework that can help you quickly understand the core principles of a web framework. If thi

Jul 14, 2022
based on go lang build WEB development framework for go lang beginners .

based on go lang build WEB development framework for go lang beginners .

Oct 31, 2021
Rocinante is a gin inspired web framework built on top of net/http.

Rocinante Rocinante is a gin inspired web framework built on top of net/http. ⚙️ Installation $ go get -u github.com/fskanokano/rocinante-go ⚡️ Quicks

Jul 27, 2021
High performance, minimalist Go web framework
High performance, minimalist Go web framework

Supported Go versions As of version 4.0.0, Echo is available as a Go module. Therefore a Go version capable of understanding /vN suffixed imports is r

Jan 2, 2023
Gearbox :gear: is a web framework written in Go with a focus on high performance
Gearbox :gear: is a web framework written in Go with a focus on high performance

gearbox ⚙️ is a web framework for building micro services written in Go with a focus on high performance. It's built on fasthttp which is up to 10x fa

Jan 3, 2023
hiboot is a high performance web and cli application framework with dependency injection support

Hiboot - web/cli application framework About Hiboot is a cloud native web and cli application framework written in Go. Hiboot is not trying to reinven

Nov 20, 2022
Package macaron is a high productive and modular web framework in Go.
Package macaron is a high productive and modular web framework in Go.

Macaron Package macaron is a high productive and modular web framework in Go. Getting Started The minimum requirement of Go is 1.6. To install Macaron

Jan 2, 2023