glhf
glhf copied to clipboard
Generic Lightweight Handler Framework
GLHF
Generic Light-weight Handler Framework
Experimental
This is a experimental library. The goal is to evaluate leveraging generics to reduce duplicate code around deserializing and serializing http requests/responses.
GLHF is used in various production apps but caution should be used. We will be continually modifying GLHF.
Installation
GLHF is versioned using go modules. To install it, run
go get -u github.com/VauntDev/glhf
Use
GLHF is a simple library that abstracts common http patterns while aiming to not prevent more complex use cases.
Options
GLHF uses an options pattern. Options can be passed directly into the Http Method functions.
i.e glhf.Get(myhandler, WithDefaultContentType("application/proto"))
- WithDefaultContentType: set the default contentType that should be used.
- WithVerbose: enables verbose error responses, useful for developers that are running into error reading/writing http objects.
More options will be added over time, check the godocs for future options.
Marshaling
Request and Response marshaling is handled in glfh by utilizing the following HTTP headers
- Content-Type: GLHF Content-type to determine how to marshal and unmarshal the request and response.
- Accept : GLHF uses the request Accept header to determine what Content-Type should be used by the response.
Currenly glhf only support Application/json
and Application/proto
. The default is Application/json
.
HTTP Routers
GLHF works with any http router that uses http.handlerFunc
functions.
Standard Library HTTP Mux
mux := http.NewServeMux()
mux.HandleFunc("/todo", glhf.Post(h.CreateTodo))
mux.HandleFunc("/todo/{id}", glhf.Get(h.LookupTodo))
Gorilla mux
mux := mux.NewRouter()
mux.HandleFunc("/todo", glhf.Post(h.CreateTodo))
mux.HandleFunc("/todo/{id}", glhf.Get(h.LookupTodo))
Future Work
- GLHF router
- cache support RFC 9111
Examples
A sample application can be found in the example directory.
The following is an example GET handler. The functions expects an empty body and Todo body in response.
func (h *Handlers) LookupTodo(r *glhf.Request[glhf.EmptyBody], w *glhf.Response[pb.Todo]) {
p := mux.Vars(r.HTTPRequest())
id, ok := p["id"]
if !ok {
w.SetStatus(http.StatusInternalServerError)
return
}
todo, err := h.service.Get(id)
if err != nil {
w.SetStatus(http.StatusNotFound)
return
}
w.Body = todo
log.Println("external handler", w.Body)
w.SetStatus(http.StatusOK)
return
}
The following is an example POST handler. The function expects a Todo body and Todo response.
func (h *Handlers) CreateTodo(r *glhf.Request[pb.Todo], w *glhf.Response[glhf.EmptyBody]) {
t, err := r.Body()
if err != nil {
w.SetStatus(http.StatusBadRequest)
return
}
if err := h.service.Add(t); err != nil {
w.SetStatus(http.StatusInternalServerError)
return
}
w.SetStatus(http.StatusOK)
return
}