janice

package module
v1.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2021 License: MIT Imports: 1 Imported by: 2

README

Janice

Build Status codecov Go Report Card

Janice simplifies middleware chaining in Go HTTP applications. It is heavily inspired by both Alice and Negroni, but with a focus on simplifying handler functions by removing error handling boilerplate.

Getting started

go get github.com/stevecallear/janice
http.ListenAndServe(":8080", janice.New(middlewareFunc).Then(handlerFunc))

Handlers

Janice uses the following signature for HTTP handler functions. This allows error handling to be moved outside of handler functions and into common middleware:

func(w http.ResponseWriter, r *http.Request) error

Middleware

Middleware functions simply return a handler that wraps in input function with additional logic, for example:

func middleware(n janice.HandlerFunc) janice.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) error {
		log.Println("before handler")
		err := n(w, r)
		log.Println("after handler")
		return err
	}
}

Middleware can be combined using either the New or Append functions, for example:

a := janice.New(m1, m2)
b := a.Append(m3)
c := a.Append(m4, m5)

Middleware chains can be converted to an http.Handler implementation using the Then function. By default any errors that make it through the middleware chain will result in http.StatusInternalServerError being written to the response. It is possible to customise this using the ErrorFn property. For example, the following will log any errors, leaving the status code unchanged:

h := janice.New(middlewareFunc).Then(handlerFunc)
h.ErrorFn = func(_ http.ResponseWriter, _ *http.Request, err error) {
	log.Printf("error: %v", err)
}

janice.Wrap and janice.WrapFunc allow http.Handler and http.HandlerFunc implementations to be used in middleware chains. For example:

mux := http.NewServeMux()
mux.Handle("/", handler)
janice.New(middleware).Then(janice.Wrap(mux))

Example

The following example creates two middleware chains: the first is applied to the route and handles any errors returned by the handler function, while the second is applied to the mux to log incoming requests.

package main

import (
	"errors"
	"log"
	"net/http"

	"github.com/stevecallear/janice"
)

func main() {
	mux := http.NewServeMux()
	mux.Handle("/", janice.New(errorHandling).Then(func(w http.ResponseWriter, r *http.Request) error {
		if e := r.URL.Query().Get("err"); e != "" {
			return errors.New(e)
		}
		return nil
	}))
	http.ListenAndServe(":8080", janice.New(requestLogging).Then(janice.Wrap(mux)))
}

func requestLogging(n janice.HandlerFunc) janice.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) error {
		log.Printf("%s %s\n", r.Method, r.URL.Path)
		return n(w, r)
	}
}

func errorHandling(n janice.HandlerFunc) janice.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) error {
		if err := n(w, r); err != nil {
			log.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
		}
		return nil
	}
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler struct {
	ErrorFn func(http.ResponseWriter, *http.Request, error)
	// contains filtered or unexported fields
}

Handler represents an HTTP handler

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type HandlerFunc

type HandlerFunc func(http.ResponseWriter, *http.Request) error

HandlerFunc represents an HTTP handler func

func Wrap

func Wrap(h http.Handler) HandlerFunc

Wrap wraps the specified HTTP handler

func WrapFunc

func WrapFunc(h http.HandlerFunc) HandlerFunc

WrapFunc wraps the specified HTTP handler function

type MiddlewareFunc

type MiddlewareFunc func(HandlerFunc) HandlerFunc

MiddlewareFunc represents an HTTP middleware func

func New

New returns a new middleware chain containing the specified functions

func (MiddlewareFunc) Append

Append appends the specified middleware function to the chain

func (MiddlewareFunc) Then

func (m MiddlewareFunc) Then(h HandlerFunc) *Handler

Then wraps the specified handler with the middleware chain

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL