Golang REST application folder structure

I'm just getting started with Go and as my first project I decided to create a simple REST API server. Unfortunately I ran into a problem as I cannot find a better way to structure my project.

So far, I use the same structure as the Rails project, meaning having controllers and models in their own folders, but this is not as idiomatic as go code.

Does anyone have any advice on how to properly structure a project?

+3


source to share


2 answers


It's probably possible, but static compilation will leave you with a bit of a mess if you want a lot of Rails automata to figure out routes.

I would probably just have a package models

with all the database models and then something Gorilla mux based on to link some routes to some actions.



If things get complicated, you can try a larger framework like Revel , which might be more suitable for a larger MVC application.

+2


source


Save the project in one folder. Go treats subfolders as separate packages. Here's a sample CMS application: https://github.com/calebdoxsey/tutorials/tree/master/appengine/cms .

I created a file that defines routes in a function init

: (using httprouter )

router.GET("/api/documents/:id", serveDocumentsGet)

      

Basically each endpoint gets its own function:

func serveDocumentsGet(res http.ResponseWriter, req *http.Request, params httprouter.Params) {
    serveAPI(res, req, func() interface{} {
        ctx := appengine.NewContext(req)
        session, _ := sessionStore.Get(req, "session")
        email, ok := session.Values["email"].(string)
        if !ok {
            return HTTPError{403, "access denied"}
        }
        userKey := datastore.NewKey(ctx, "User", email, 0, nil)
        docKey := datastore.NewKey(ctx, "Document", params.ByName("id"), 0, userKey)
        var document Document
        err := datastore.Get(ctx, docKey, &document)
        if err != nil {
            return err
        }
        return document
    })
}

      

serveAPI

is just a handy function for handling json encoding and errors:



func serveAPI(res http.ResponseWriter, req *http.Request, handler func() interface{}) {
    res.Header().Set("Content-Type", "application/json")

    result := handler()
    if err, ok := result.(HTTPError); ok {
        res.WriteHeader(err.Code)
        json.NewEncoder(res).Encode(map[string]string{
            "error": err.Message,
        })
    } else if err, ok := result.(error); ok {
        res.WriteHeader(500)
        json.NewEncoder(res).Encode(map[string]string{
            "error": err.Error(),
        })
    } else if rc, ok := result.(io.ReadCloser); ok {
        io.Copy(res, rc)
        rc.Close()
    } else {
        json.NewEncoder(res).Encode(result)
    }
}

      

I mostly try to avoid magic, so all endpoints are pretty explicit.

This gives you controllers and models (for more complex models, I split them into separate files ... see user example).

For views, you can use the built in go template template. Create a folder (maybe static/tpl/yourtemplate.gohtml

) and use template.ParseFiles

it tpl.Execute

to render them too. (once again this is obvious ... no magic)

But more and more often I find that most of my views are done client-side using javascript. If you do this, you only need to specify the files:

static := http.FileServer(http.Dir("static"))
router.GET("/static/*filepath", func(res http.ResponseWriter, req *http.Request, params httprouter.Params) {
    filepath := params.ByName("filepath")
    req.URL.Path = filepath
    static.ServeHTTP(res, req)
})

      

-2


source







All Articles