Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Handler

MIT License Go Doc

Usage

Handler is a collection of common http.Handlers used in Go web applications, typically REST APIs. These handlers integrate well with applications that use the Handler Constructor pattern:

type Constructor func(r *http.Request) http.Handler

Please see the example for a working example.

Why use the Handler Constructor pattern?

Well, it depends. Take a look at the following examples:

Using the conventional pattern

func CreateProduct(w http.ResponseWriter, r *http.Request) {
	var p *Product
	if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	
	if err := db.Insert(p); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(p); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

Using the Handler Constructor pattern

func CreateProduct(r *http.Request) http.Handler {
	var p *Product
	if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
		return handler.Error(http.StatusBadRequest, err)
	}
	
	if err := db.Insert(p); err != nil {
		return handler.Error(http.StatusInternalServerError, err)
	}
	
	return handler.JSON(http.StatusCreated, p)
}

Hopefully, at least two things stick out:

  • The Handler Constructor pattern allows for early function departures without requiring an empty return statement. This should feel intuitive with how much we encounter return err statements.
  • We don't even see w http.ResponseWriter in our constructor, making it much more difficult to make the mistake of writing to w when we shouldn't (e.g. multiple times). It is easier for this type of mistake to occur using the conventional pattern, say, forgetting an empty return statement after calling http.Error. Note that you can get access to w in your constructor by returning a http.HandlerFunc.

When to not use the Handler Constructor pattern

The points made above are enough to convince me to use this pattern for most of my Go applications; but not all of them. Here are some reasons you may want avoid using the handler.Constructor pattern:

  • You need to stream data to the http.ResponseWriter.
  • You find yourself frequently needing access to w http.ResponseWriter directly - to the point where the majority of your constructors become nothing more than wrappers around http.HandlerFuncs.

Routing

The Constructor type satisfies the http.Handler interface, so they can be used anywhere a http.Handler can. Here is an example using Handler Constructors with gorilla/mux:

package main

import (
        "log"
        "net/http"

        "github.com/gorilla/mux"
        "github.com/zpatrick/handler"
)

func Index(r *http.Request) http.Handler {
        return handler.String(http.StatusOK, "Hello, World!")
}

func main() {
        r := mux.NewRouter()
        r.Handle("/", handler.Constructor(Index))

        log.Println("Listening on port 8000")
        log.Fatal(http.ListenAndServe(":8000", r))
}

About

Collection of common http.Handlers for Go applications

Topics

Resources

License

Releases

No releases published

Packages

No packages published

Languages

You can’t perform that action at this time.