influxdb/http/README.md

90 lines
2.4 KiB
Markdown
Raw Normal View History

# HTTP Handler Style Guide
### HTTP Handler
* Each handler should implement `http.Handler`
- This can be done by embedding a [`httprouter.Router`](https://github.com/julienschmidt/httprouter)
(a light weight HTTP router that supports variables in the routing pattern and matches against the request method)
* Required services should be exported on the struct
```go
// ThingHandler represents an HTTP API handler for things.
type ThingHandler struct {
// embedded httprouter.Router as a lazy way to implement http.Handler
*httprouter.Router
ThingService platform.ThingService
AuthorizationService platform.AuthorizationService
Logger *zap.Logger
}
```
### HTTP Handler Constructor
* Routes should be declared in the constructor
```go
// NewThingHandler returns a new instance of ThingHandler.
func NewThingHandler() *ThingHandler {
h := &ThingHandler{
Router: httprouter.New(),
Logger: zap.Nop(),
}
h.HandlerFunc("POST", "/v2/things", h.handlePostThing)
h.HandlerFunc("GET", "/v2/things", h.handleGetThings)
return h
}
```
### Route handlers (`http.HandlerFunc`s)
* Each route handler should have an associated request struct and decode function
* The decode function should take a `context.Context` and an `*http.Request` and return the associated route request struct
```go
type postThingRequest struct {
Thing *platform.Thing
}
func decodePostThingRequest(ctx context.Context, r *http.Request) (*postThingRequest, error) {
t := &platform.Thing{}
if err := json.NewDecoder(r.Body).Decode(t); err != nil {
return nil, err
}
return &postThingRequest{
Thing: t,
}, nil
}
```
* Route `http.HandlerFuncs` should separate the decoding and encoding of HTTP requests/response from actual handler logic
```go
// handlePostThing is the HTTP handler for the POST /v2/things route.
func (h *ThingHandler) handlePostThing(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := decodePostThingRequest(ctx, r)
if err != nil {
errors.EncodeHTTP(ctx, err, w)
return
}
// Do stuff here
if err := h.ThingService.CreateThing(ctx, req.Thing); err != nil {
errors.EncodeHTTP(ctx, err, w)
return
}
if err := encodeResponse(ctx, w, http.StatusCreated, req.Thing); err != nil {
h.Logger.Info("encoding response failed", zap.Error(err))
return
}
}
```
* `http.HandlerFunc`'s that require particular encoding of http responses should implement an encode response function