Skip to content

provide (http-server) middlewares and (http-client) tripperwares

License

Notifications You must be signed in to change notification settings

gol4ng/httpware

Folders and files

NameName
Last commit message
Last commit date

Latest commit

5d1c519 · Nov 4, 2019

History

36 Commits
Nov 4, 2019
Nov 4, 2019
Nov 4, 2019
Aug 27, 2019
Nov 4, 2019
Nov 2, 2019
Jul 23, 2019
Aug 27, 2019
Jul 23, 2019
Nov 4, 2019
Nov 4, 2019
Aug 27, 2019
Nov 2, 2019
Oct 30, 2019
Nov 4, 2019
Oct 30, 2019
Nov 4, 2019

Repository files navigation

gol4ng/httpware: middleware/tripperware

Build Status Maintainability Test Coverage Go Report Card GoDoc

httpware

Package httpware is a collection of middleware (net/http.Handler wrapper) and tripperware (net/http.RoundTripper wrapper)

  • CorrelationId gets or creates a correlation_id and adds it to the http.request Context and in the http.response header (in order to propagate this ID throught all microservices)
  • Metrics will use a given Recorder to collect inflight request(current parrallel request count), request duration and response size.
Name Middleware Tripperware
CorrelationId X X
Metrics X X

Installation

go get -u github.com/gol4ng/httpware

Quick Start

Client side

package main

import (
	"net/http"
	"os"
	"runtime"
	
	"github.com/gol4ng/httpware/v2"
	"github.com/gol4ng/httpware/v2/tripperware"
)

func main(){
    // create http client with correlationId activated
    client := &http.Client{
        Transport: tripperware.CorrelationId(),
    }
    
    _, _ = client.Get("fake-address.foo")
    // request will have Header "Correlation-Id: <randomID(10)>"
}

Server side

package main

import (
	"fmt"
	"net/http"
	"os"
	"runtime"
	
	"github.com/gol4ng/httpware/v2"
	"github.com/gol4ng/httpware/v2/correlation_id"
	"github.com/gol4ng/httpware/v2/middleware"
)

func main(){
    port:= ":8001"
    srv := http.NewServeMux()
    srv.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
        // Correlation-Id come directly from the client or was generated by the middleware
        fmt.Println(request.Header.Get(correlation_id.HeaderName))
        writer.WriteHeader(http.StatusOK)
    })
    
    go func() {
        if err := http.ListenAndServe(port, middleware.CorrelationId()(srv)); err != nil {
            panic(err)
        }
    }()
}

Middlewares

A middleware is an http.Handler decorator, its role is to wrap arround http.Handler or another middleware

A middleware stack is a collection of middleware ([]Middleware) that acts has a single Middleware (Append/Prepend).

A stack allows you to DecorateHandler and DecorateHandlerFunc

Tripperwares

A tripperware is an http.RoundTripper decorator, its role is to wrap arround http.RoundTripper or another tripperware

A tripperware stack is a collection of tripperware ([]Tripperware) that acts has a single Tripperware (RoundTrip/DecorateClient/Append/Prepend).

A stack allows you to DecorateRoundTripper and DecorateRoundTripFunc.

Decorate existing client

You can decorate an existing http.Client

client := &http.Client{}
   
// when you decorate client you can set second arg to true if you want a copy
tripperware.CorrelationId().DecorateClient(client, false)
    
_, _ = client.Get("fake-address.foo")
// request will have Header "Correlation-Id: <randomID(10)>"

Act has http.RoundTripper

A tripperware can be use has an http.RoundTripper

tripperware.CorrelationId() == tripperware.CorrelationId()(http.DefaultTransport)

client := &http.Client{
    Transport:tripperware.CorrelationId(),
}
    
_, _ = client.Get("fake-address.foo")
// request will have Header "Correlation-Id: <randomID(10)>"

Become a tripperware stack

The Append and Prepend functions will convert a tripperware into a []Tripperware

roundTripper := tripperware.CorrelationId()
roundTripper.Prepend(func(t http.RoundTripper) http.RoundTripper {
    return httpware.RoundTripFunc(func(req *http.Request) (*http.Response, error) {
        fmt.Println("http request headers :", req.Header)
        return t.RoundTrip(req)
    })
})

client := &http.Client{
    Transport:roundTripper,
}

_, _ = client.Get("fake-address.foo")
// request will have Header "Correlation-Id: <randomID(10)>"

Stack computation

The stack is gonna be computed when you decorate the final round tripper.

m1, m2, m3 are middlewares

[m1, m2, m3].DecorateHandler(<yourHandler>) == m1( m2( m3( <yourHandler> ) ) )

t1 t2 t3 are tripperwares

[t1, t2, t3].DecorateRoundTripper(<yourTripper>) == t1( t2( t3( <yourTripper> ) ) )

	tripperware := func(before, after string) httpware.Tripperware {
		return func(t http.RoundTripper) http.RoundTripper {
			return httpware.RoundTripFunc(func(req *http.Request) (*http.Response, error) {
				defer fmt.Println(after) // will print string AFTER child round trip executed
				fmt.Println(before) // will print string BEFORE child round trip executed
				return t.RoundTrip(req)
			})
		}
	}

	stack := httpware.TripperwareStack(
		tripperware("A before", "A after"),
		tripperware("B before", "B after"),
		tripperware("C before", "C after"),
		tripperware("D before", "D after"),
	)
	// A( B( C( D( http.DefaultTransport ) ) ) )

	client := &http.Client{
		Transport: stack,
	}
	_, _ = client.Get("http://localhost/")
	//Output:
	//A before
	//B before
	//C before
	//D before
	//D after
	//C after
	//B after
	//A after