Skip to content

VauntDev/glhf

Repository files navigation

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

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
}