A minimal http framework that includes some useful tools. Inspired by Flask.
- Easy to learn API.
- Views handle your data only e.g. no template logic (Single-responsibility principle).
- Define HTTP methods per View method.
- Middleware - add yor own middleware
- Auth
- Logging
- CORS
- JSON
- Access request arguments
- Static files
go get github.com/joegasewicz/gomek
c := gomek.Config{
BaseTemplateName: "layout",
BaseTemplates: []string{
"./templates/layout.gohtml",
},
}
// Create a new gomek app
app := gomek.New(c)
// Declare your views
app.Route("/blog").View(blog).Methods("GET", "POST").Templates("./templates/blog.gohtml")
// Add middleware
app.Use(gomek.Logging) // Use gomek's Logging
app.Use(gomek.CORS) // Use gomek's CORS
// Set a port (optional)
app.Listen(6011)
// Start your app
app.Start()
There are 2 types of handlers
- Handlers that render templates
- Handlers that return JSON / text .etc
// A view that handles a template's data
func index(w http.ResponseWriter, r *http.Request, d *gomek.Data) {
templateData := make(gomek.Data)
// templateData["Title"] = "Hello!"
*d = templateData
}
// A view that just returns JSON
func blog(w http.ResponseWriter, r *http.Request, data *gomek.Data) {
var blog Blog
// query database then return JSON
gomek.JSON(w, blog, http.StatusOK)
}
Access the request route arguments inside a handler
args := gomek.Args(r)
Return a JSON response from within a handler
gomek.JSON(w, blog)
Development CORS only
app := gomek.New(gomek.Config{})
app.Use(gomek.CORS)
Set the base templates via the BaseTemplates
method
app := gomek.New(gomek.Config{BaseTemplateName: "layout"})
app.BaseTemplates("./template/layout.html". "./templates/hero.html")
If you want to assign multiple verbs to the same route then use the following method clause
app.Route("/blog").View(blog).Methods("GET", "POST")
func index(w http.ResponseWriter, r *http.Request, d *gomek.Data) {
if r.Method == "GET" {
// code for GET requests to /blogs
}
if r. Method == "POST" {
// code for POST requests to /blog
}
// .etc...
If you use the gomek.Authorize
middleware, all your routes will need to pass authorization
via the callback function passed to gomek.Authorize
. To whitelist routes, pass a list of string
pairs, representing the path and the request method, respectively.
var whiteList = [][]string{
{
"/", "GET",
},
{
"/login", "GET",
},
}
The gomek.Authorize
middleware function require 2 arguments, your [][]string
of path / request methods
and a callback function to test your auth strategy (e.g. session or JWT).
app.Use(gomek.Authorize(whiteList, func(r *http.Request) (bool, context.Context) {
// if your authorization test passes then return true
return true, nil
}))
You can also attach values of any type to the request context
app.Use(gomek.Authorize(whiteList, func(r *http.Request) (bool, context.Context) {
// You can attach values to the request context & returning the context also
ctx := context.WithValue(r.Context(), "userID", 1)
return true, ctx
}))
// Create a type that represents your resource
type Notice struct {
}
// Implement the `Resource` interface
func (n *Notice) Post(w http.ResponseWriter, request *http.Request, d *gomek.Data) {
panic("implement me")
}
func (n *Notice) Put(w http.ResponseWriter, request *http.Request, d *gomek.Data) {
panic("implement me")
}
func (n *Notice) Delete(w http.ResponseWriter, r *http.Request, d *gomek.Data) {
panic("implement me")
}
func (n *Notice) Get(w http.ResponseWriter, r *http.Request, d *gomek.Data) {
var notice schemas.Notice
notice.Name = "Joe!"
gomek.JSON(w, notice, http.StatusOK)
}
To use your implementation of the Resource
type
// The Resource method expects a type that implements the `Resource` interface.
app.Route("/notices").Resource(&routes.Notice{}).Methods("GET")
app.Route("/blogs/<blog_id>").View(GetBlogs).Methods("GET", "POST")
func GetBlogs(w http.ResponseWriter, r *http.Request, d *gomek.Data) {
vars := gomek.Args(r)
advertId := vars["blog_id"]
GetParams returns slices of string
// example request url - http://127.0.0.1:8080/users?user_id=1
userID, err := gomek.GetParams(r, "user_id")
if err != nil {
log.Println("no user_id in params")
return
}
// userID[0] = "1"
Set the machine's host
app.SetHost("127.0.0.1")
**Not specific to Gomek (example implements the standard library's static files setup)
app := gomek.New(gomek.Config{})
publicFiles := http.FileServer(http.Dir("public"))
app.Handle("/public/", http.StripPrefix("/public/", publicFiles))
Gomek provides a testing utility that returns a regular HandlerFunc
gomek.CreateTestHandler
c := Config{}
mockApp := NewTestApp(c)
mockApp.Route("/blogs").Methods("POST").Resource(&Notice{})
mockApp.Start()
notice := Notice{}
handler := gomek.CreateTestHandler(mockApp, notice.Post)
req := httptest.NewRequest(http.MethodPost, "/blogs", nil)
w := httptest.NewRecorder()
handler(w, req) // regular HandlerFunc
resp := w.Result()
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("Error: %v", err)
}
expected := `{"name":"Joe"}`
if string(data) != expected {
t.Errorf("Expected %s got '%v'", expected, string(data))