/kitchen

A simple bootstrap for my own web projects

Primary LanguageGoMIT LicenseMIT

kitchen

Build Status Coverage Status

A very simple bootstrap for my web project, based on alice and negroni and context package.

How?

Its very simple to handle a request in net/http package, and kitchen just add a simple middleware system to that, like this :

package main

import (
	"log"
	"net/http"

	"github.com/fzerorubigd/kitchen"
)

type midleware struct {
	next http.Handler
}

func (m *midleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	krw, ok := w.(kitchen.ResponseWriter)
	if !ok {
		panic("wtf?")
	}
	krw.SetWithValue("test", "from middleware!")

	// Call the next middleware
	m.next.ServeHTTP(w, r)
}

func newExampleMiddleware(next http.Handler) http.Handler {
	return &midleware{next}
}

func main() {

	req := func(w http.ResponseWriter, r *http.Request) {
		krw, ok := w.(kitchen.ResponseWriter)
		if !ok {
			panic("wtf?")
		}
		test, ok := krw.Context().Value("test").(string)
		if !ok {
			panic("wtf?")
		}

		w.Write([]byte(test))
	}

	http.Handle(
		"/",
		kitchen.NewChain(newExampleMiddleware).ThenFunc(req),
	)

	log.Fatal(http.ListenAndServe(":9091", nil))
}

the middleware system, always add a responseWriterWrap middleware at the begining, so the first argument is always kitchen.ResponseWriter. The default context is a cancel context and after finishing the request, the cancel function is triggered and you can watch for Done channel in Context() if you need to know the request is delivered and its time to give up.

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/fzerorubigd/kitchen"
)

type midleware struct {
	next http.Handler
}

func (m *midleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	krw, ok := w.(kitchen.ResponseWriter)
	if !ok {
		panic("wtf?")
	}

	start := time.Now()
	log.Println("New request...")

	go func() {
		<-krw.Context().Done()
		latency := time.Since(start)
		log.Println(r.URL.Path, krw.Status(), krw.Context().Err(), latency)
	}()

	m.next.ServeHTTP(w, r) // Call the next one
}

func newExampleMiddleware(next http.Handler) http.Handler {
	return &midleware{next}
}

func main() {

	req := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("See terminal for log."))
	}

	http.Handle(
		"/",
		kitchen.NewChain(newExampleMiddleware).ThenFunc(req),
	)

	log.Fatal(http.ListenAndServe(":9091", nil))
}

See this article about context.

There is some example, not fully tested middleware in middlewares sub package, but just use them as example, anything may change there.