middleware

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2024 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package middleware contains common used HTTP-server middlewares:

  • RequireRequestId
  • RequestLogger
  • Recoverer

... and DefaultChain func to add those middlewares to http-handler.

All middlewares are compatible with std http.Handler

Index

Examples

Constants

This section is empty.

Variables

View Source
var ConnectionHeader = textproto.CanonicalMIMEHeaderKey("connection")
View Source
var (
	XRequestIDHeader = textproto.CanonicalMIMEHeaderKey("x-request-id")
)

Functions

func Chain

func Chain(h http.Handler, middlewares ...func(next http.Handler) http.Handler) http.Handler

Chain wraps the handler with provided middlewares:

h = mw_0(mw_1( ... mw_N-1(mw_N(h)) ... ))

func DefaultChain

func DefaultChain(h http.Handler, log *app.Logger) http.Handler

DefaultChain adds the following middlewares to the handler:

  • RequireRequestId
  • RequestLogger(log)
  • Recoverer(WithLogger(log))
Example
log := app.NewLogger(stdout{}, app.WithLogLevel(slog.LevelInfo))
h := middleware.DefaultChain(http.HandlerFunc(okHandler), log)

rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)
req.Header.Set(middleware.XRequestIDHeader, "XXX-YYY")

h.ServeHTTP(rr, req)

fmt.Println("response:", rr.Body.String())
Output:

{"time":"2006-01-02T15:05:06.000000000+07:00","level":"INFO","msg":"request completed","component":"middleware/RequestLogger","method":"GET","path":"/","remote_addr":"","user_agent":"","resp_code":200,"bytes":12,"resp_time":"1ms","request_id":"XXX-YYY"}
response: XXX-YYY - OK

func Recoverer

func Recoverer(log *app.Logger) func(next http.Handler) http.Handler

Recoverer catches handler panic, log it and send http.StatusInternalServerError to client

Example
log := app.NewLogger(stdout{}, app.WithLogLevel(slog.LevelInfo))
recoverer := middleware.Recoverer(log)

h := recoverer(http.HandlerFunc(panicHandler))
rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)

h.ServeHTTP(rr, req)
Output:

{"time":"2006-01-02T15:05:06.000000000+07:00","level":"ERROR","msg":"fatal error","component":"middleware/Recoverer","error":"FATAL!!!","stacktrace":"..."}

func RequestLogger

func RequestLogger(log *app.Logger) func(next http.Handler) http.Handler

RequestLogger logs requests using provided logger

Checks response code:

  • if 0 < code < http.StatusBadRequest logs INFO
  • otherwise logs ERROR
Example (Bad)
log := app.NewLogger(stdout{}, app.WithLogLevel(slog.LevelInfo))
rl := middleware.RequestLogger(log)

h := rl(http.HandlerFunc(badHandler))

rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)

h.ServeHTTP(rr, req)
Output:

{"time":"2006-01-02T15:05:06.000000000+07:00","level":"ERROR","msg":"request failed","component":"middleware/RequestLogger","method":"GET","path":"/","remote_addr":"","user_agent":"","resp_code":400,"bytes":7,"resp_time":"1ms"}
Example (Ok)
log := app.NewLogger(stdout{}, app.WithLogLevel(slog.LevelInfo))
rl := middleware.RequestLogger(log)

h := rl(http.HandlerFunc(okHandler))

rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)

h.ServeHTTP(rr, req)
Output:

{"time":"2006-01-02T15:05:06.000000000+07:00","level":"INFO","msg":"request completed","component":"middleware/RequestLogger","method":"GET","path":"/","remote_addr":"","user_agent":"","resp_code":200,"bytes":5,"resp_time":"1ms"}

func RequireRequestId

func RequireRequestId(next http.Handler) http.Handler

RequireRequestId checks if XRequestIDHeader exists.

If ok, adds request id into context. If not, sends error response with ErrCodeValidation

Example (Bad)
h := middleware.RequireRequestId(http.HandlerFunc(okHandler))

rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)

h.ServeHTTP(rr, req)
fmt.Println("response:", rr.Code, rr.Body.String())
Output:

response: 400 {"error":"ERR_VALIDATION","message":"X-Request-Id header is required"}
Example (Ok)
h := middleware.RequireRequestId(http.HandlerFunc(okHandler))

rr := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/", nil)
req.Header.Set(middleware.XRequestIDHeader, "XXX-YYY")

h.ServeHTTP(rr, req)
fmt.Println("response:", rr.Code, rr.Body.String())
Output:

response: 200 XXX-YYY - OK

Types

This section is empty.

Jump to

Keyboard shortcuts

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