Documentation ¶
Index ¶
- Constants
- Variables
- func APIAuth(next http.Handler) http.Handler
- func APIAuthOptional(next http.Handler) http.Handler
- func AllowContentEncoding(contentEncoding ...string) func(next http.Handler) http.Handler
- func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler
- func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler
- func CleanPath(next http.Handler) http.Handler
- func Compress(level int, types ...string) func(next http.Handler) http.Handler
- func ContentCharset(charsets ...string) func(next http.Handler) http.Handler
- func GetHead(next http.Handler) http.Handler
- func GetReqID(ctx context.Context) string
- func GetUserID(r *phi.Request) (*primitive.ObjectID, *phi.Error)
- func Heartbeat(endpoint string) func(http.Handler) http.Handler
- func JWTAuth(next http.Handler) http.Handler
- func JWTAuthOptional(next http.Handler) http.Handler
- func JWTOrAPIAuth(next http.Handler) http.Handler
- func JWTOrAPIAuthOptional(next http.Handler) http.Handler
- func Logger(next http.Handler) http.Handler
- func Maybe(mw func(http.Handler) http.Handler, maybeFn func(r *http.Request) bool) func(http.Handler) http.Handler
- func New(h http.Handler) func(next http.Handler) http.Handler
- func NextRequestID() uint64
- func NoCache(h http.Handler) http.Handler
- func PageRoute(path string, handler http.Handler) func(http.Handler) http.Handler
- func PathRewrite(old, new string) func(http.Handler) http.Handler
- func PrintPrettyStack(rvr interface{})
- func Profiler() http.Handler
- func RealIP(h http.Handler) http.Handler
- func Recoverer(next http.Handler) http.Handler
- func RedirectSlashes(next http.Handler) http.Handler
- func RequestID(next http.Handler) http.Handler
- func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler
- func SetHeader(key, value string) func(next http.Handler) http.Handler
- func SetTokenCheckFunc(fn func(username, password string) (*Token, error))
- func SetUnauthorizedFunc(fn func() *phi.Error)
- func StripSlashes(next http.Handler) http.Handler
- func Throttle(limit int) func(http.Handler) http.Handler
- func ThrottleBacklog(limit, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler
- func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler
- func Timeout(timeout time.Duration) func(next http.Handler) http.Handler
- func URLFormat(next http.Handler) http.Handler
- func WithLogEntry(r *http.Request, entry LogEntry) *http.Request
- func WithValue(key, val interface{}) func(next http.Handler) http.Handler
- type Compressor
- type DefaultLogFormatter
- type EncoderFunc
- type HeaderRoute
- type HeaderRouter
- func (hr HeaderRouter) Handler(next http.Handler) http.Handler
- func (hr HeaderRouter) Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
- func (hr HeaderRouter) RouteAny(header string, match []string, ...) HeaderRouter
- func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter
- type LogEntry
- type LogFormatter
- type LoggerInterface
- type Pattern
- type TOKEN_TYPE
- type ThrottleOpts
- type Token
- type WrapResponseWriter
Constants ¶
const RequestIDKey ctxKeyRequestID = 0
RequestIDKey is the key that holds the unique request ID in a request context.
Variables ¶
var ( // LogEntryCtxKey is the context.Context key to store the request log entry. LogEntryCtxKey = &contextKey{"LogEntry"} // DefaultLogger is called by the Logger middleware handler to log each request. // Its made a package-level variable so that it can be reconfigured for custom // logging configurations. DefaultLogger func(next http.Handler) http.Handler )
var IsTTY bool
var RequestIDHeader = "X-Request-Id"
RequestIDHeader is the name of the HTTP Header which contains the request id. Exported so that it can be changed by developers
var ( // URLFormatCtxKey is the context.Context key to store the URL format data // for a request. URLFormatCtxKey = &contextKey{"URLFormat"} )
Functions ¶
func APIAuth ¶ added in v0.1.0
Checks for basic authentication and returns unauthorized if not found
unauthorized response can be set via SetTokenCheckFunc
Can be used for api authentication, middleware expects basic header at every request, token is more likely to be longer available and should not be exposed to the client
Tokens can be extracted like one of the following:
token := r.Context().Value(middleware.TOKEN_CONTEXT).(middleware.Token) token := phi.GetToken(r) // only works with *phi.Request
func APIAuthOptional ¶ added in v0.1.0
Same as APIAuth but continues without adding the token if unauthorized
Can be used for cases where an authenticated user will receive a different response but still has access to the ressource
func AllowContentEncoding ¶
AllowContentEncoding enforces a whitelist of request Content-Encoding otherwise responds with a 415 Unsupported Media Type status.
func AllowContentType ¶
AllowContentType enforces a whitelist of request Content-Types otherwise responds with a 415 Unsupported Media Type status.
func BasicAuth ¶
BasicAuth implements a simple middleware handler for adding basic http auth to a route.
func CleanPath ¶
CleanPath middleware will clean out double slash mistakes from a user's request path. For example, if a user requests /users//1 or //users////1 will both be treated as: /users/1
func Compress ¶
Compress is a middleware that compresses response body of a given content types to a data format based on Accept-Encoding request header. It uses a given compression level.
NOTE: make sure to set the Content-Type header on your response otherwise this middleware will not compress the response body. For ex, in your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody)) or set it manually.
Passing a compression level of 5 is sensible value
func ContentCharset ¶
ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match. An empty charset will allow requests with no Content-Type header or no specified charset.
func GetReqID ¶
GetReqID returns a request ID from the given context if one is present. Returns the empty string if a request ID cannot be found.
func GetUserID ¶ added in v0.1.0
Opinionated helper function to get the user id from the token as primitive.ObjectID
func Heartbeat ¶
Heartbeat endpoint middleware useful to setting up a path like `/ping` that load balancers or uptime testing external services can make a request before hitting any routes. It's also convenient to place this above ACL middlewares as well.
func JWTAuth ¶ added in v0.1.0
Checks for bearer token and returns unauthorized if not found
unauthorized response can be set via SetTokenCheckFunc
Can be used for frontend authentication, middleware expects jwt token at every request, needs to be refreshed after expiry
Tokens can be extracted like one of the following:
token := r.Context().Value(middleware.TOKEN_CONTEXT).(middleware.Token) token := phi.GetToken(r) // only works with *phi.Request
func JWTAuthOptional ¶ added in v0.1.0
Same as JWTAuth but continues without adding the token if unauthorized
Can be used for cases where an authenticated user will receive a different response but still has access to the ressource
func JWTOrAPIAuth ¶ added in v0.1.0
Checks for bearer token or basic auth and returns unauthorized if not found
unauthorized response can be set via SetTokenCheckFunc
Can be used for endpoints which are gonna be used for a frontend and from an api at the same time
Tokens can be extracted like one of the following:
token := r.Context().Value(middleware.TOKEN_CONTEXT).(middleware.Token) token := phi.GetToken(r) // only works with *phi.Request
func JWTOrAPIAuthOptional ¶ added in v0.1.0
Same as JWTOrAPIAuth but continues without adding the token if unauthorized
Can be used for cases where an authenticated user will receive a different response but still has access to the ressource
func Logger ¶
Logger is a middleware that logs the start and end of each request, along with some useful data about what was requested, what the response status was, and how long it took to return. When standard output is a TTY, Logger will print in color, otherwise it will print in black and white. Logger prints a request ID if one is provided.
Alternatively, look at https://github.com/goware/httplog for a more in-depth http logger with structured logging support.
IMPORTANT NOTE: Logger should go before any other middleware that may change the response, such as middleware.Recoverer. Example:
r := phi.NewRouter() r.Use(middleware.Logger) // <--<< Logger should come before Recoverer r.Use(middleware.Recoverer) r.Get("/", handler)
func Maybe ¶
func Maybe(mw func(http.Handler) http.Handler, maybeFn func(r *http.Request) bool) func(http.Handler) http.Handler
Maybe middleware will allow you to change the flow of the middleware stack execution depending on return value of maybeFn(request). This is useful for example if you'd like to skip a middleware handler if a request does not satisfied the maybeFn logic.
func NextRequestID ¶
func NextRequestID() uint64
NextRequestID generates the next request ID in the sequence.
func NoCache ¶
NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent a router (or subrouter) from being cached by an upstream proxy and/or client.
As per http://wiki.nginx.org/HttpProxyModule - NoCache sets:
Expires: Thu, 01 Jan 1970 00:00:00 UTC Cache-Control: no-cache, private, max-age=0 X-Accel-Expires: 0 Pragma: no-cache (for HTTP/1.0 proxies/clients)
func PageRoute ¶
PageRoute is a simple middleware which allows you to route a static GET request at the middleware stack level.
func PathRewrite ¶
PathRewrite is a simple middleware which allows you to rewrite the request URL path.
func PrintPrettyStack ¶
func PrintPrettyStack(rvr interface{})
func Profiler ¶
Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
func MyService() http.Handler { r := phi.NewRouter() // ..middlewares r.Mount("/debug", middleware.Profiler()) // ..routes return r }
func RealIP ¶
RealIP is a middleware that sets a http.Request's RemoteAddr to the results of parsing either the True-Client-IP, X-Real-IP or the X-Forwarded-For headers (in that order).
This middleware should be inserted fairly early in the middleware stack to ensure that subsequent layers (e.g., request loggers) which examine the RemoteAddr will see the intended value.
You should only use this middleware if you can trust the headers passed to you (in particular, the two headers this middleware uses), for example because you have placed a reverse proxy like HAProxy or nginx in front of phi. If your reverse proxies are configured to pass along arbitrary header values from the client, or if you use this middleware without a reverse proxy, malicious clients will be able to make you very sad (or, depending on how you're using RemoteAddr, vulnerable to an attack of some sort).
func Recoverer ¶
Recoverer is a middleware that recovers from panics, logs the panic (and a backtrace), and returns a HTTP 500 (Internal Server Error) status if possible. Recoverer prints a request ID if one is provided.
Alternatively, look at go.philip.id/phi/httplog middleware pkgs.
func RedirectSlashes ¶
RedirectSlashes is a middleware that will match request paths with a trailing slash and redirect to the same path, less the trailing slash.
NOTE: RedirectSlashes middleware is *incompatible* with http.FileServer, see go.philip.id/phi/phi/issues/343
func RequestID ¶
RequestID is a middleware that injects a request ID into the context of each request. A request ID is a string of the form "host.example.com/random-0001", where "random" is a base62 random string that uniquely identifies this go process, and where the last number is an atomically incremented request counter.
func RequestLogger ¶
func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler
RequestLogger returns a logger handler using a custom LogFormatter.
func SetTokenCheckFunc ¶ added in v0.1.0
set new tokencheck function, f.e.. check username, password against a database
Example (mongopiet):
func TokenCheck(username, password string) (*Token, error) { token, err := database.FindOne("apiTokens", bson.M{"token": username}) if err != nil { return nil, errors.New("not found") } return &phi.Token{ ID: a.User.Hex(), Subject: a.Subject, } }
func SetUnauthorizedFunc ¶ added in v0.1.0
SetUnauthorizedFunc sets the function to be called when a request is unauthorized
default is phi.Unauthorized
func StripSlashes ¶
StripSlashes is a middleware that will match request paths with a trailing slash, strip it from the path and continue routing through the mux, if a route matches, then it will serve the handler.
func Throttle ¶
Throttle is a middleware that limits number of currently processed requests at a time across all users. Note: Throttle is not a rate-limiter per user, instead it just puts a ceiling on the number of currentl in-flight requests being processed from the point from where the Throttle middleware is mounted.
func ThrottleBacklog ¶
func ThrottleBacklog(limit, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler
ThrottleBacklog is a middleware that limits number of currently processed requests at a time and provides a backlog for holding a finite number of pending requests.
func ThrottleWithOpts ¶
func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler
ThrottleWithOpts is a middleware that limits number of currently processed requests using passed ThrottleOpts.
func Timeout ¶
Timeout is a middleware that cancels ctx after a given timeout and return a 504 Gateway Timeout error to the client.
It's required that you select the ctx.Done() channel to check for the signal if the context has reached its deadline and return, otherwise the timeout signal will be just ignored.
ie. a route/handler may look like:
r.Get("/long", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() processTime := time.Duration(rand.Intn(4)+1) * time.Second select { case <-ctx.Done(): return case <-time.After(processTime): // The above channel simulates some hard work. } w.Write([]byte("done")) })
func URLFormat ¶
URLFormat is a middleware that parses the url extension from a request path and stores it on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will trim the suffix from the routing path and continue routing.
Routers should not include a url parameter for the suffix when using this middleware.
Sample usage.. for url paths: `/articles/1`, `/articles/1.json` and `/articles/1.xml`
func routes() http.Handler { r := phi.NewRouter() r.Use(middleware.URLFormat) r.Get("/articles/{id}", ListArticles) return r } func ListArticles(w http.ResponseWriter, r *http.Request) { urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string) switch urlFormat { case "json": render.JSON(w, r, articles) case "xml:" render.XML(w, r, articles) default: render.JSON(w, r, articles) } }
func WithLogEntry ¶
WithLogEntry sets the in-context LogEntry for a request.
Types ¶
type Compressor ¶
type Compressor struct {
// contains filtered or unexported fields
}
Compressor represents a set of encoding configurations.
func NewCompressor ¶
func NewCompressor(level int, types ...string) *Compressor
NewCompressor creates a new Compressor that will handle encoding responses.
The level should be one of the ones defined in the flate package. The types are the content types that are allowed to be compressed.
func (*Compressor) Handler ¶
func (c *Compressor) Handler(next http.Handler) http.Handler
Handler returns a new middleware that will compress the response based on the current Compressor.
func (*Compressor) SetEncoder ¶
func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc)
SetEncoder can be used to set the implementation of a compression algorithm.
The encoding should be a standardised identifier. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
For example, add the Brotli algortithm:
import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc" compressor := middleware.NewCompressor(5, "text/html") compressor.SetEncoder("br", func(w http.ResponseWriter, level int) io.Writer { params := brotli_enc.NewBrotliParams() params.SetQuality(level) return brotli_enc.NewBrotliWriter(params, w) })
type DefaultLogFormatter ¶
type DefaultLogFormatter struct { Logger LoggerInterface NoColor bool }
DefaultLogFormatter is a simple logger that implements a LogFormatter.
func (*DefaultLogFormatter) NewLogEntry ¶
func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry
NewLogEntry creates a new LogEntry for the request.
type EncoderFunc ¶
An EncoderFunc is a function that wraps the provided io.Writer with a streaming compression algorithm and returns it.
In case of failure, the function should return nil.
type HeaderRoute ¶
type HeaderRoute struct { Middleware func(next http.Handler) http.Handler MatchOne Pattern MatchAny []Pattern }
func (HeaderRoute) IsMatch ¶
func (r HeaderRoute) IsMatch(value string) bool
type HeaderRouter ¶
type HeaderRouter map[string][]HeaderRoute
func RouteHeaders ¶
func RouteHeaders() HeaderRouter
RouteHeaders is a neat little header-based router that allows you to direct the flow of a request through a middleware stack based on a request header.
For example, lets say you'd like to setup multiple routers depending on the request Host header, you could then do something as so:
r := phi.NewRouter() rSubdomain := phi.NewRouter()
r.Use(middleware.RouteHeaders().
Route("Host", "example.com", middleware.New(r)). Route("Host", "*.example.com", middleware.New(rSubdomain)). Handler)
r.Get("/", h) rSubdomain.Get("/", h2)
Another example, imagine you want to setup multiple CORS handlers, where for your origin servers you allow authorized requests, but for third-party public requests, authorization is disabled.
r := phi.NewRouter()
r.Use(middleware.RouteHeaders().
Route("Origin", "https://app.skyweaver.net", cors.Handler(cors.Options{ AllowedOrigins: []string{"https://api.skyweaver.net"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"}, AllowCredentials: true, // <----------<<< allow credentials })). Route("Origin", "*", cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Content-Type"}, AllowCredentials: false, // <----------<<< do not allow credentials })). Handler)
func (HeaderRouter) Route ¶
func (hr HeaderRouter) Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
func (HeaderRouter) RouteAny ¶
func (hr HeaderRouter) RouteAny(header string, match []string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter
func (HeaderRouter) RouteDefault ¶
func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter
type LogEntry ¶
type LogEntry interface { Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) Panic(v interface{}, stack []byte) }
LogEntry records the final log when a request completes. See defaultLogEntry for an example implementation.
func GetLogEntry ¶
GetLogEntry returns the in-context LogEntry for a request.
type LogFormatter ¶
LogFormatter initiates the beginning of a new LogEntry per request. See DefaultLogFormatter for an example implementation.
type LoggerInterface ¶
type LoggerInterface interface {
Print(v ...interface{})
}
LoggerInterface accepts printing to stdlib logger or compatible logger.
type TOKEN_TYPE ¶ added in v0.1.0
type TOKEN_TYPE string
const TOKEN_CONTEXT TOKEN_TYPE = "_token"
Use this type to get/set the token from the context
type ThrottleOpts ¶
type ThrottleOpts struct { RetryAfterFn func(ctxDone bool) time.Duration Limit int BacklogLimit int BacklogTimeout time.Duration }
ThrottleOpts represents a set of throttling options.
type Token ¶ added in v0.1.0
func ImplementAccessCheck ¶ added in v0.1.0
default implementation of token check, wont work in production!
type WrapResponseWriter ¶
type WrapResponseWriter interface { http.ResponseWriter // Status returns the HTTP status of the request, or 0 if one has not // yet been sent. Status() int // BytesWritten returns the total number of bytes sent to the client. BytesWritten() int // Tee causes the response body to be written to the given io.Writer in // addition to proxying the writes through. Only one io.Writer can be // tee'd to at once: setting a second one will overwrite the first. // Writes will be sent to the proxy before being written to this // io.Writer. It is illegal for the tee'd writer to be modified // concurrently with writes. Tee(io.Writer) // Unwrap returns the original proxied target. Unwrap() http.ResponseWriter }
WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook into various parts of the response process.
func NewWrapResponseWriter ¶
func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter
NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to hook into various parts of the response process.
Source Files ¶
- auth.go
- basic_auth.go
- clean_path.go
- compress.go
- content_charset.go
- content_encoding.go
- content_type.go
- get_head.go
- heartbeat.go
- logger.go
- maybe.go
- middleware.go
- nocache.go
- page_route.go
- path_rewrite.go
- profiler.go
- realip.go
- recoverer.go
- request_id.go
- route_headers.go
- strip.go
- terminal.go
- throttle.go
- timeout.go
- url_format.go
- value.go
- wrap_writer.go