-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
37ad04d
commit 2ae32e7
Showing
3 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
logo.png export-ignore | ||
.gitattributes export-ignore | ||
.gitignore export-ignore | ||
.travis.yml export-ignore | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,194 @@ | ||
<img src="logo.png" alt="gol4ng/httpware: middleware/tripperware" title="provide middleware/tripperware" align="right" width="200px"> | ||
|
||
[](https://travis-ci.com/gol4ng/httpware) | ||
[](https://codeclimate.com/github/gol4ng/httpware/maintainability) | ||
[](https://codeclimate.com/github/gol4ng/httpware/test_coverage) | ||
[](https://goreportcard.com/report/github.com/gol4ng/httpware) | ||
[](https://godoc.org/github.com/gol4ng/httpware) | ||
|
||
# httpware | ||
|
||
Package httpware is a collection of middleware (net/http.Handler wrapper) and tripperware (net/http.RoundTripper wrapper) | ||
|
||
- **CorrelationId** that get or create a `correlation_id` and add it to the `http.request` Context and in `http.response` header (in order to propagate this ID throught all microservice) | ||
- **Metrics** it will use 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 | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
"os" | ||
"runtime" | ||
|
||
"github.com/gol4ng/httpware" | ||
"github.com/gol4ng/httpware/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 | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"runtime" | ||
|
||
"github.com/gol4ng/httpware" | ||
"github.com/gol4ng/httpware/correlation_id" | ||
"github.com/gol4ng/httpware/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 a `http.Handler` decorator, his role is to wrap arround `http.Handler` or another middleware | ||
|
||
A middleware stack is a collection of middleware (`[]Middleware`) that act has single Middleware (Append/Prepend). | ||
A stack allow you to DecorateHandler and DecorateHandlerFunc | ||
|
||
|
||
## Tripperwares | ||
|
||
A tripperware is a `http.RoundTripper` decorator, his role is to wrap arround `http.RoundTripper` or another tripperware | ||
|
||
A tripperware stack is a collection of tripperware (`[]Tripperware`) that act has single Tripperware (RoundTrip/DecorateClient/Append/Prepend). | ||
|
||
A stack allow you to DecorateRoundTripper and DecorateRoundTripFunc. | ||
|
||
### Decorate existing client | ||
|
||
You can decorate existing `http.Client` | ||
|
||
```go | ||
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 `http.RoundTripper` | ||
> `tripperware.CorrelationId() == tripperware.CorrelationId()(http.DefaultTransport)` | ||
```go | ||
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` `Prepend` functions will convert tripperware into `[]Tripperware` | ||
|
||
```go | ||
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 gonna be compute when you decorate final round tripper. | ||
|
||
m1, m2, m3 are middleware | ||
|
||
`[m1, m2, m3].DecorateHandler(<yourHandler>) == m1( m2( m3( <yourHandler> ) ) )` | ||
|
||
t1 t2 t3 are tripperware | ||
|
||
`[t1, t2, t3].DecorateRoundTripper(<yourTripper>) == t1( t2( t3( <yourTripper> ) ) )` | ||
|
||
```go | ||
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 | ||
``` |