Documentation
ΒΆ
Index ΒΆ
- Variables
- func AppendLogAttrs(ctx context.Context, attrs ...slog.Attr)
- func Bind(r *http.Request, v any) (err error)
- func CSV(w http.ResponseWriter, r *http.Request, status int, rows [][]string)
- func CSVIter(w http.ResponseWriter, r *http.Request, status int, ...)
- func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, rerr *ResolvedError)
- func DefaultLogRequestLeveler(r *http.Request, statusCode int) slog.Level
- func Error(w http.ResponseWriter, r *http.Request, errs ...error)
- func ErrorWithCode(w http.ResponseWriter, r *http.Request, statusCode int, errs ...error)
- func GetContextIP(ctx context.Context) net.IP
- func GetLogAttrs(ctx context.Context) []slog.Attr
- func GetRequestID(ctx context.Context) string
- func GetRequestIDOrHeader(ctx context.Context, r *http.Request) string
- func IfError(w http.ResponseWriter, r *http.Request, errs ...error) bool
- func IsDebug(ctx context.Context) bool
- func IsExposableError(err error) bool
- func JSON(w http.ResponseWriter, r *http.Request, status int, v any)
- func Log(ctx context.Context, lvl slog.Level, msg string, attrs ...slog.Attr)
- func LogDebug(ctx context.Context, msg string, attrs ...slog.Attr)
- func LogError(ctx context.Context, msg string, attrs ...slog.Attr)
- func LogInfo(ctx context.Context, msg string, attrs ...slog.Attr)
- func LogWarn(ctx context.Context, msg string, attrs ...slog.Attr)
- func NewServer(ctx context.Context, logger *slog.Logger, srv *http.Server, ...) error
- func NewServerWithoutDefaults(ctx context.Context, logger *slog.Logger, srv *http.Server, ...) error
- func Run(pctx context.Context, logger *slog.Logger, srv *http.Server, ...) error
- func RunTLS(pctx context.Context, logger *slog.Logger, srv *http.Server, ...) error
- func SecureRedirect(w http.ResponseWriter, r *http.Request, status int, target string)
- func SecureRedirectOrNext(w http.ResponseWriter, r *http.Request, status int, fallback string)
- func SetLogError(ctx context.Context, rerr *ResolvedError)
- func SkipNextURL(r *http.Request) *http.Request
- func UseAPIKeyRequired(keys []string, header string) func(next http.Handler) http.Handler
- func UseAPIVersionMatch(version, header string) func(next http.Handler) http.Handler
- func UseContextIP() func(next http.Handler) http.Handler
- func UseCrossOriginProtection(rules ...string) func(next http.Handler) http.Handler
- func UseCrossOriginProtectionFunc(cond CrossOriginValidator) func(next http.Handler) http.Handler
- func UseCrossOriginResourceSharing(config *CORSConfig) func(next http.Handler) http.Handler
- func UseDebug(debug bool) func(next http.Handler) http.Handler
- func UseHeaders(headers map[string]string) func(next http.Handler) http.Handler
- func UseIf(cond bool, handler func(http.Handler) http.Handler) func(http.Handler) http.Handler
- func UseIfFunc(mw func(next http.Handler) http.Handler, cond func(r *http.Request) bool) func(next http.Handler) http.Handler
- func UseNextURL() func(next http.Handler) http.Handler
- func UsePrivateIP() func(next http.Handler) http.Handler
- func UseRealIP(config *RealIPConfig) func(next http.Handler) http.Handler
- func UseRealIPStringOpts(options []string) func(next http.Handler) http.Handler
- func UseRecoverer(next http.Handler) http.Handler
- func UseRequestID() func(next http.Handler) http.Handler
- func UseRobotsText(config *RobotsTextConfig) func(next http.Handler) http.Handler
- func UseSecurityText(config SecurityTextConfig) func(next http.Handler) http.Handler
- func UseStatic(config *StaticConfig) http.Handler
- func UseStripSlashes() func(next http.Handler) http.Handler
- func UseStructuredLogger(config *LogConfig) func(http.Handler) http.Handler
- func XML(w http.ResponseWriter, r *http.Request, status int, v any)
- type CORSConfig
- type Config
- func (c *Config) AddErrorResolvers(resolvers ...ErrorResolverFn) *Config
- func (c *Config) Clone() *Config
- func (c *Config) GetAPIBasePath() string
- func (c *Config) GetErrorHandler() ErrorHandler
- func (c *Config) GetErrorResolvers() []ErrorResolverFn
- func (c *Config) GetJSONDecoder() JSONDecoder
- func (c *Config) GetJSONEncoder() JSONEncoder
- func (c *Config) GetLogger() *slog.Logger
- func (c *Config) GetMaskPrivateErrors() bool
- func (c *Config) GetRequestDecoder() RequestDecoder
- func (c *Config) GetRequestIDHeader() string
- func (c *Config) GetRequestValidator() RequestValidator
- func (c *Config) SetAPIBasePath(path string) *Config
- func (c *Config) SetErrorHandler(handler ErrorHandler) *Config
- func (c *Config) SetErrorResolvers(resolvers ...ErrorResolverFn) *Config
- func (c *Config) SetJSONDecoder(decoder JSONDecoder) *Config
- func (c *Config) SetJSONEncoder(encoder JSONEncoder) *Config
- func (c *Config) SetLogger(logger *slog.Logger) *Config
- func (c *Config) SetMaskPrivateErrors(enabled bool) *Config
- func (c *Config) SetRequestDecoder(decoder RequestDecoder) *Config
- func (c *Config) SetRequestIDHeader(header string) *Config
- func (c *Config) SetRequestValidator(validator RequestValidator) *Config
- func (c *Config) Use() func(next http.Handler) http.Handler
- type CrossOriginValidator
- type DefaultErrorBody
- type ErrorHandler
- type ErrorResolverFn
- type ErrorVisibility
- type ExposableError
- type JSONDecoder
- type JSONEncoder
- type LogConfig
- type LogSchema
- type LogSchemaID
- type M
- type RealIPConfig
- type RealIPHeaderParser
- type RequestDecoder
- type RequestValidator
- type ResolvedError
- type RobotsTextConfig
- type RobotsTextRule
- type SecurityTextConfig
- type StaticConfig
- type Validatable
Constants ΒΆ
This section is empty.
Variables ΒΆ
var ( ErrCrossOriginRequest = errors.New("cross-origin request detected from Sec-Fetch-Site header") ErrCrossOriginRequestOldBrowser = errors.New("cross-origin request detected, and/or browser is out of date: Sec-Fetch-Site is missing, and Origin does not match Host") )
var ( ErrAccessDenied = errors.New("access denied") ErrAPIKeyInvalid = errors.New("invalid api key provided") ErrAPIKeyMissing = errors.New("api key not specified") ErrNoAPIKeys = errors.New("no api keys provided in initialization") ErrAPIVersionMissing = errors.New("api version not specified") ErrAPIVersionMismatch = errors.New("server and client version mismatch") )
var BuiltinLogSchemas = []LogSchemaID{ LogSchemaSimple, LogSchemaECS, LogSchemaLegacy, }
Functions ΒΆ
func AppendLogAttrs ΒΆ
AppendLogAttrs appends the given attributes to the log entry in the context. Use this to annotate logs when using UseStructuredLogger, and when using Log, LogDebug, LogInfo, LogWarn, and LogError.
func Bind ΒΆ
Bind binds various request attributes to the given struct, including query parameters, form data (multipart/form-data included), JSON bodies, etc, in addition to validating the struct. It calls both Config.GetRequestDecoder and Config.GetRequestValidator to perform the necessary operations. Behind the scenes, both go-playground/form and go-playground/validator are used to perform the necessary operations.
Example:
type User struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Pretty bool `form:"pretty"`
}
func (u *User) Validate() error {
if u.Name == "system" {
return errors.New("system users are not allowed")
}
return nil
}
func main() {
// [...]
r.Post("/user", func(w http.ResponseWriter, r *http.Request) {
var user User
if err := chix.Bind(r, &user); err != nil {
chix.Error(w, r, err)
return
}
// [... more request-specific logic...]
w.WriteHeader(http.StatusOK)
})
}
References:
func CSVIter ΒΆ
CSVIter marshals rows from the associated iterator to CSV, and setting the Content-Type as text/csv. If the iterator returns an error, the error will be returned and the response will be set to a 500 internal server error, otherwise the rows are written to a buffer, which will be written once the iterator is exhausted.
func DefaultErrorHandler ΒΆ
func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, rerr *ResolvedError)
DefaultErrorHandler is the default error handler that will be used if no other error handler is provided. It will automatically mask 5xx+ errors if they are not configured to be public. If a custom API base path is provided through Config.SetAPIBasePath, if the request matches that base path, it will respond with DefaultErrorBody as JSON, otherwise will be a generic plain-text error response.
func DefaultLogRequestLeveler ΒΆ
DefaultLogRequestLeveler determines the log level for a given request and response status code. The following request/response attributes define how the level is determined:
- statusCode >= 500: ERROR
- statusCode == 429: INFO
- statusCode >= 400: WARN
- method == OPTIONS: DEBUG
- default: INFO
func Error ΒΆ
func Error(w http.ResponseWriter, r *http.Request, errs ...error)
Error handles errors in an HTTP request. At least one error must be specified (see IfError if you want to simplify if-error-then-respond logic). This function will do some cursory resolution of the errors based on what was provided (e.g. you can pass a ResolvedError directly to customize how something is resolved, e.g. custom status code, marking an error as public, etc), in addition to passing the error to the configured list of error resolvers (see Config.SetErrorResolvers). It will then pass the resolved error to the configured error handler (see Config.SetErrorHandler).
Panics if no errors were provided.
func ErrorWithCode ΒΆ
ErrorWithCode is a helper function that allows you to set a specific status code for an error. It will wrap the error in a ResolvedError and pass it to the Error function. If the status code is <500 (and no error resolvers or ExposableError implementations are used), the error will be marked as public. If this is not desired, you can use Error directly instead, and provide your own ResolvedError with the [Public] field set to false.
func GetContextIP ΒΆ
GetContextIP can be used to retrieve the IP from the context, that was previously set by UseContextIP. If no IP was set, nil is returned.
func GetLogAttrs ΒΆ
GetLogAttrs returns the attributes that have been added to the log entry in the context.
func GetRequestID ΒΆ
GetRequestID returns a request ID from the context if present, otherwise "".
func GetRequestIDOrHeader ΒΆ
GetRequestIDOrHeader returns a request ID from the context if present, otherwise the request header, if present. The header can be changed using Config.SetRequestIDHeader.
func IfError ΒΆ
IfError is a helper function that allows you to check if an error is present, and if so, call Error to handle it, and returning true.
Example:
if chix.IfError(w, r, Something(foo, bar)) {
return // Response already handled.
}
// [... more request-specific logic...]
func IsExposableError ΒΆ
IsExposableError returns true if the error is safe to be exposed to the client. If the error implements the ExposableError interface, it will be used to determine if the error is public. Otherwise, it will return false. Accounts for ResolvedError, and will return the [ExposableError.Public] result.
func JSON ΒΆ
JSON marshals 'v' to JSON, and setting the Content-Type as application/json. Note that this does NOT auto-escape HTML.
JSON also supports indented output when the origin request has "?pretty=true" or similar.
func Log ΒΆ
Log logs a message at the given level, with the given attributes. This includes any attributes which have been added by AppendLogAttrs or SetLogError.
TODO: make this always include the request ID.
func LogDebug ΒΆ
LogDebug logs a message at the debug level, with the given attributes. This includes any attributes which have been added by AppendLogAttrs or SetLogError.
func LogError ΒΆ
LogError logs a message at the error level, with the given attributes. This includes any attributes which have been added by AppendLogAttrs or SetLogError.
func LogInfo ΒΆ
LogInfo logs a message at the info level, with the given attributes. This includes any attributes which have been added by AppendLogAttrs or SetLogError.
func LogWarn ΒΆ
LogWarn logs a message at the warn level, with the given attributes. This includes any attributes which have been added by AppendLogAttrs or SetLogError.
func NewServer ΒΆ
func NewServer( ctx context.Context, logger *slog.Logger, srv *http.Server, certFile, keyFile string, ) error
NewServer runs the HTTP server (with sane/safe defaults set), including with graceful termination, so when the context is cancelled, the server will be gracefully terminated (with a max timeout of 60 seconds), waiting for all requests to complete. If certFile and keyFile are provided, the server will be run with TLS enabled.
func NewServerWithoutDefaults ΒΆ
func NewServerWithoutDefaults( ctx context.Context, logger *slog.Logger, srv *http.Server, certFile, keyFile string, ) error
NewServerWithoutDefaults runs the HTTP server, including with graceful termination, so when the context is cancelled, the server will be gracefully terminated (with a max timeout of 60 seconds), waiting for all requests to complete. If certFile and keyFile are provided, the server will be run with TLS enabled.
func Run ΒΆ
func Run( pctx context.Context, logger *slog.Logger, srv *http.Server, jobs ...scheduler.Job, ) error
Run runs the HTTP server (with sane/safe defaults set), including with graceful termination. When the context is cancelled, the server will be gracefully terminated (with a max timeout of 60 seconds), waiting for all requests to complete. You can pass additional scheduler jobs, which allows additional asynchronous tasks/cron-jobs to be run alongside the HTTP server.
This will also listen for OS signals (SIGINT, SIGTERM, SIGQUIT) and gracefully terminate the server and all jobs when received.
func RunTLS ΒΆ
func RunTLS( pctx context.Context, logger *slog.Logger, srv *http.Server, certFile, keyFile string, jobs ...scheduler.Job, ) error
RunTLS runs the HTTP server (with sane/safe defaults set) with TLS support, including with graceful termination. When the context is cancelled, the server will be gracefully terminated (with a max timeout of 60 seconds), waiting for all requests to complete. You can pass additional scheduler jobs, which allows additional asynchronous tasks/cron-jobs to be run alongside the HTTP server.
This will also listen for OS signals (SIGINT, SIGTERM, SIGQUIT) and gracefully terminate the server and all jobs when received.
func SecureRedirect ΒΆ
SecureRedirect supports validating that redirect requests fulfill the following conditions:
Target URL must match one of:
- Absolute/relative to the same host
- http or https, with a host matching the requested host (no cross-domain, no port matching).
- Target URL can be parsed by net/url.Parse.
Additionally, if using UseNextURL middleware, see SecureRedirectOrNext for advanced redirect logic.
func SecureRedirectOrNext ΒΆ
SecureRedirectOrNext is a helper function that will redirect to the next URL if it is stored in the session (using UseNextURL), otherwise it will redirect to the fallback URL, using SecureRedirect. See SecureRedirect for more details on the set of rules that are enforced when redirecting/security checks.
Use this for advanced multi-step authentication flows, where a frontend (for example), can pass in "?next=<URL>" to redirect to after authentication is complete, which is persisted in a cookie across multiple requests.
func SetLogError ΒΆ
func SetLogError(ctx context.Context, rerr *ResolvedError)
SetLogError sets the error that occurred in the request/response in the context. Not required when using Error and similar functions, as they will automatically set the error in the context for you.
func SkipNextURL ΒΆ
SkipNextURL is a help that will prevent the next URL (if any), that is loaded by UseNextURL from being used during a redirect. This is useful when you have to redirect to another source first.
func UseAPIKeyRequired ΒΆ
UseAPIKeyRequired is a middleware that checks if the request has the correct API keys provided in the associated header. Returns net/http.StatusUnauthorized if an invalid key is provided, and net/http.StatusPreconditionFailed if no key header is provided.
If no header is provided, the default header "X-Api-Key" will be used.
func UseAPIVersionMatch ΒΆ
UseAPIVersionMatch is a middleware that checks if the request has the correct API version provided in the associated header.
If no header is provided, the default header "X-Api-Version" will be used.
func UseContextIP ΒΆ
UseContextIP can be used to add the requests IP to the context. This is beneficial for passing the request context to a request-unaware function/method/service, that does not have access to the original request. Ensure that this middleware is registered after UseRealIP, otherwise the stored IP may be incorrect.
func UseCrossOriginProtection ΒΆ
UseCrossOriginProtection implements protections against Cross-Site Request Forgery (CSRF) by rejecting non-safe cross-origin browser requests. It will check if the request is from a trusted origin, and if not, it will return a 403 Forbidden error. It uses the Sec-Fetch-Site and Origin headers to determine if the request is trusted. GET, HEAD, and OPTIONS methods are safe methods and are always allowed. Rules should be provided in one of the following formats:
- Trusted origin: "scheme://host[:port]" (e.g. "https://example.com", "http://localhost:8080")
- Glob pattern: "*.example.com" (e.g. "*.example.com" which is http/https, "https://*.example.com").
func UseCrossOriginProtectionFunc ΒΆ
func UseCrossOriginProtectionFunc(cond CrossOriginValidator) func(next http.Handler) http.Handler
UseCrossOriginProtectionFunc is an alternative to UseCrossOriginProtection that allows you to provide a custom condition function to determine if the request is trusted. Note that the origin URL may not be provided in the request. In that scenario, unless you have a specific path that you want to bypass, you should return false.
func UseCrossOriginResourceSharing ΒΆ
func UseCrossOriginResourceSharing(config *CORSConfig) func(next http.Handler) http.Handler
UseCrossOriginResourceSharing is a middleware that implements the CORS spec. It will set the appropriate headers for the request based on the existence of CORS headers. Follows the CORS spec as close as possible. See also.
func UseDebug ΒΆ
UseDebug is a middleware that allows passing if debugging is enabled for the http server. Use IsDebug to check if debugging is enabled.
func UseHeaders ΒΆ
UseHeaders is a convenience handler to set multiple response header key/value pairs. Similar to go-chi's SetHeader, but allows for multiple headers to be set at once.
func UseIf ΒΆ
UseIf is a conditional middleware that only uses the provided middleware if the condition is true, otherwise continues as normal.
func UseIfFunc ΒΆ
func UseIfFunc(mw func(next http.Handler) http.Handler, cond func(r *http.Request) bool) func(next http.Handler) http.Handler
UseIfFunc is a conditional middleware that only uses the provided middleware if the condition function returns true, otherwise continues as normal.
func UseNextURL ΒΆ
UseNextURL is a middleware that will store the current URL provided via the "next" query parameter, as a cookie in the response, for use with multi-step authentication flows. This allows the user to be redirected back to the original destination after authentication. Must use SecureRedirect to redirect the user, which will pick up the url from the cookie.
func UsePrivateIP ΒΆ
UsePrivateIP can be used to allow only private IP's to access specific routes. Make sure to register this middleware after UseRealIP, otherwise the IP checking may be incorrect.
func UseRealIP ΒΆ
func UseRealIP(config *RealIPConfig) func(next http.Handler) http.Handler
UseRealIP is a middleware that allows passing the real IP address of the client only if the request headers that include an override, come from a trusted proxy.
func UseRealIPStringOpts ΒΆ
UseRealIPStringOpts is a convenience function that wraps UseRealIP, with support for configuring the middleware via CLI/string flags. You can pass in an array that contains a mix of different supported headers.
Supported options are provided below:
- "cloudflare", "cf-connecting-ip": trust cloudflare ranges, and use Cf-Connecting-Ip header.
- "x-forwarded-for": use X-Forwarded-For header.
- "x-real-ip": use X-Real-Ip header.
- "true-client-ip": use True-Client-Ip header.
- "*", "any", "all": trust any IP and use X-Forwarded-For header.
- "local", "localhost", "bogon", "internal", "private": trust private IP ranges.
- any other string is treated as a trusted IP or CIDR.
If no options are passed in, DefaultRealIPConfig is used.
func UseRecoverer ΒΆ
UseRecoverer is a middleware that recovers from panics, and responds with a 500 status code and appropriate error message. If debug is enabled, through UseDebug, a stack trace will be printed to stderr. Do not use this middleware if you use UseStructuredLogger middleware, as it already handles panics (in a similar way).
NOTE: This middleware should be loaded after logging/request-id/use-debug, etc middleware, but before the handlers that may panic.
func UseRequestID ΒΆ
UseRequestID is a middleware that injects a request ID into the context of each request. If the connecting client provides a request ID in the request header, it will be used instead. If no request ID is provided, a new request ID will be generated. To change which header is referenced, use Config.SetRequestIDHeader.
func UseRobotsText ΒΆ
func UseRobotsText(config *RobotsTextConfig) func(next http.Handler) http.Handler
UseRobotsText returns a handler that serves a robots.txt file.
func UseSecurityText ΒΆ
func UseSecurityText(config SecurityTextConfig) func(next http.Handler) http.Handler
UseSecurityText returns a handler that serves a security.txt file at the standardized path(s). Only the provided fields will be included in the response.
func UseStatic ΒΆ
func UseStatic(config *StaticConfig) http.Handler
UseStatic returns a handler that serves static files from the provided embedded filesystem, with support for using the direct filesystem when debugging is enabled. It also supports serviing Single Page Applications (SPA) by redirecting all files not found, to the [StaticConfig.Fallback] file, if configured through [StaticConfig.SPA].
Example usage:
//go:embed all:public/dist
var publicDist embed.FS
[...]
router.Mount("/static", chix.UseStatic(&chix.StaticConfig{
FS: publicDist,
Prefix: "/static",
AllowLocal: true,
Path: "public/dist"
}))
func UseStripSlashes ΒΆ
UseStripSlashes is a middleware that strips trailing slashes from the URL path, and accounts for the pprof /debug/ path, which breaks when slahes are stripped. Use github.com/go-chi/chi/v5/middleware.StripSlashes instead if you don't need this functionality.
func UseStructuredLogger ΒΆ
UseStructuredLogger is a middleware that logs the request and response as a structured log entry. It uses the LogConfig to determine the log level, and what the schema of the log entry should be. See DefaultLogConfig for the default configuration, which can be customized.
NOTE:
- This can recover from panics (and always will, to log them, regardless the [LogConfig.RecoverPanics] setting, but will re-throw if panic recovery is disabled), and will always log the request/response in that scenario. This means that if [LogConfig.RecoverPanics] is enabled, you do not need to use UseRecoverer middleware after this one.
- This should be loaded after request-id type middleware, but before everything else.
- AppendLogAttrs can be used to add extra attributes to the log entry.
- GetLogAttrs can be used to get the attributes that have been added to the log entry, if you want to use them in other middleware or handlers.
- SetLogError can be used to set the error that occurred in the request/response, though if using Error and similar functions, this is automatically done for you.
Types ΒΆ
type CORSConfig ΒΆ
type CORSConfig struct {
// AllowedOrigins is a list of origins a cross-domain request can be executed
// from. Wildcards are supported, though there will be a small perf hit. Default
// value is "*", which allows all.
AllowedOrigins []string
// AllowOriginFunc is a custom function to validate the origin. If this returns
// true, the origin is allowed. Additionally, if headers is non-nil, the headers
// are added to the Vary header.
AllowOriginFunc func(r *http.Request, origin string) (headers []string, allowed bool)
// AllowedMethods is a list of methods the client is allowed to use with
// cross-domain requests. Default value is HEAD, GET and POST.
AllowedMethods []string
// AllowedHeaders is list of headers the client is allowed to use with
// cross-domain requests. Default is "Accept", "Content-Type", and "Origin".
// Allows "*".
AllowedHeaders []string
// ExposedHeaders indicates which headers are safe to expose.
ExposedHeaders []string
// MaxAge indicates how long the results of a preflight request can be cached.
// If not provided, no Access-Control-Max-Age header will be sent back, resulting
// in browsers using their default value (typically 5s). Using a negative value
// will tell browsers to explicitly disable caching.
MaxAge time.Duration
// AllowCredentials indicates whether the request can include user credentials
// like cookies, HTTP authentication or client side SSL certificates.
AllowCredentials bool
// AllowPrivateNetwork indicates whether to accept cross-origin requests over a
// private network.
AllowPrivateNetwork bool
// PassthroughPreflight allows other middleware/handlers to process the OPTIONS
// method, though this is typically not required.
PassthroughPreflight bool
// PreflightStatus provides a status code to use for successful preflight OPTIONS
// requests. Default is [net/http.StatusNoContent] (204).
PreflightStatus int
// contains filtered or unexported fields
}
CORSConfig configures the cross-origin resource sharing middleware.
func AllowAllCORSConfig ΒΆ
func AllowAllCORSConfig() *CORSConfig
func DefaultCORSConfig ΒΆ
func DefaultCORSConfig() *CORSConfig
func (*CORSConfig) Validate ΒΆ
func (c *CORSConfig) Validate() error
Validate validates the CORS config. Use this to validate the config before using it, otherwise UseCrossOriginResourceSharing will panic if an invalid config is provided.
type Config ΒΆ
type Config struct {
// contains filtered or unexported fields
}
Config is the configuration for the chix package.
func GetConfig ΒΆ
GetConfig returns the Config from the context, or creates a new Config if none is found.
func (*Config) AddErrorResolvers ΒΆ
func (c *Config) AddErrorResolvers(resolvers ...ErrorResolverFn) *Config
AddErrorResolvers adds additional error resolvers to the existing ones.
func (*Config) GetAPIBasePath ΒΆ
GetAPIBasePath returns the configured API base path.
func (*Config) GetErrorHandler ΒΆ
func (c *Config) GetErrorHandler() ErrorHandler
GetErrorHandler returns the configured error handler.
func (*Config) GetErrorResolvers ΒΆ
func (c *Config) GetErrorResolvers() []ErrorResolverFn
GetErrorResolvers returns the configured error resolvers.
func (*Config) GetJSONDecoder ΒΆ
func (c *Config) GetJSONDecoder() JSONDecoder
GetJSONDecoder returns the configured JSON decoder.
func (*Config) GetJSONEncoder ΒΆ
func (c *Config) GetJSONEncoder() JSONEncoder
GetJSONEncoder returns the configured JSON decoder.
func (*Config) GetMaskPrivateErrors ΒΆ
GetMaskPrivateErrors returns the configured flag for masking private errors.
func (*Config) GetRequestDecoder ΒΆ
func (c *Config) GetRequestDecoder() RequestDecoder
GetRequestDecoder returns the configured request decoder.
func (*Config) GetRequestIDHeader ΒΆ
GetRequestIDHeader returns the configured request ID header.
func (*Config) GetRequestValidator ΒΆ
func (c *Config) GetRequestValidator() RequestValidator
GetRequestValidator returns the configured request validator.
func (*Config) SetAPIBasePath ΒΆ
SetAPIBasePath sets the API base path. Defaults to "/".
func (*Config) SetErrorHandler ΒΆ
func (c *Config) SetErrorHandler(handler ErrorHandler) *Config
SetErrorHandler sets the error handler. Defaults to DefaultErrorHandler.
func (*Config) SetErrorResolvers ΒΆ
func (c *Config) SetErrorResolvers(resolvers ...ErrorResolverFn) *Config
SetErrorResolvers sets the error resolvers.
func (*Config) SetJSONDecoder ΒΆ
func (c *Config) SetJSONDecoder(decoder JSONDecoder) *Config
SetJSONDecoder sets the JSON decoder. Defaults to encoding/json or encoding/json/v2, if the experimental encoding/json/v2 is enabled for the build.
func (*Config) SetJSONEncoder ΒΆ
func (c *Config) SetJSONEncoder(encoder JSONEncoder) *Config
SetJSONEncoder sets the JSON encoder. Defaults to encoding/json or encoding/json/v2, if the experimental encoding/json/v2 is enabled for the build.
func (*Config) SetLogger ΒΆ
SetLogger sets the logger. Defaults to a [discardLogger], which discards all log records.
func (*Config) SetMaskPrivateErrors ΒΆ
SetMaskPrivateErrors sets the flag for masking private errors. If enabled, errors that are not public (like database errors) will be masked and a generic error message will be returned. This only relates to 5xx errors, not 4xx errors. Defaults to true.
func (*Config) SetRequestDecoder ΒΆ
func (c *Config) SetRequestDecoder(decoder RequestDecoder) *Config
SetRequestDecoder sets the request/body decoder. Defaults to go-playground/form's form.NewDecoder(), in addition to JSON and similar content-types.
func (*Config) SetRequestIDHeader ΒΆ
SetRequestIDHeader sets the request ID header. Defaults to "X-Request-Id".
func (*Config) SetRequestValidator ΒΆ
func (c *Config) SetRequestValidator(validator RequestValidator) *Config
SetRequestValidator sets the global request validator. Defaults to go-playground/validator's validator.New().
type DefaultErrorBody ΒΆ
type DefaultErrorBody struct {
Error string `json:"error"`
Errors []string `json:"errors,omitempty"`
Type string `json:"type"`
Code int `json:"code"`
RequestID string `json:"request_id,omitempty"`
Timestamp string `json:"timestamp"`
}
DefaultErrorBody is the default error body that will be used to render the error, used by DefaultErrorHandler.
type ErrorHandler ΒΆ
type ErrorHandler func(w http.ResponseWriter, r *http.Request, rerr *ResolvedError)
ErrorHandler is a function that, depending on the input, will either respond to a request with a given response structured based off an error or do nothing, if there isn't actually an error.
type ErrorResolverFn ΒΆ
type ErrorResolverFn func(oerr *ResolvedError) *ResolvedError
ErrorResolverFn is a function that resolves an error to a client-facing safe error, or adjusts the status code based on if it's caused by incorrect user input, etc. Resolvers are useful in situations where you want to return a different error when the error contains a database-related error (like duplicate key already exists, returning a 400 by default), for example, without having to litter your code in multiple places. If the function returns nil, it will continue through the chain of resolvers.
Example:
func ErrorResolver(oerr *chix.ResolvedError) *chix.ResolvedError {
if oerr.Err != nil {
if errors.Is(oerr.Err, sql.ErrNoRows) {
return &chix.ResolvedError{Err: errors.New("resource not found"), StatusCode: http.StatusNotFound, Visibility: chix.ErrorPublic}
}
}
return oerr
}
type ErrorVisibility ΒΆ
type ErrorVisibility int
ErrorVisibility can be used to control the visibility of an error.
const ( // ErrorUnknown is the default visibility for an error, usually when the error // originates outside of the chix package/[ErrorWithCode] functions, and usage // of [ResolvedError]. This will be calculated based on all child errors, and // the status code, to determine visibility. ErrorUnknown ErrorVisibility = iota // ErrorPublic is a visibility that indicates the error is safe to be exposed // to the client. ErrorPublic // ErrorMasked is a visibility that indicates the error is not safe to be exposed // to the client, as it may contain sensitive information. ErrorMasked )
type ExposableError ΒΆ
type ExposableError interface {
Public() bool
}
ExposableError is an interface that can be implemented by errors that can indicate if they are safe to be exposed to the client. If an error implements this interface, it will be used to determine if the error will be masked or not.
You can also use ResolvedError errors, or error resolvers to control visibility dynamically.
type JSONDecoder ΒΆ
JSONDecoder is a function that is used to unmarshal JSON data (e.g. request body), to a value.
func DefaultJSONDecoder ΒΆ
func DefaultJSONDecoder() JSONDecoder
type JSONEncoder ΒΆ
JSONEncoder is a function that is used to marshal JSON data (e.g. response body), from a value.
func DefaultJSONEncoder ΒΆ
func DefaultJSONEncoder() JSONEncoder
type LogConfig ΒΆ
type LogConfig struct {
// Level defines the minimum level to be logged. If not provided, the default
// is defined by the level of the [log/slog.Logger] provided through [Config.Logger].
// You can use this to have lower levels for most logging in your application,
// but only log warnings/errors/etc. See [DefaultLogRequestLeveler] for the default
// level determination, which can be customized.
Level *slog.Level
// Leveler can be used to customize the log level determination for a given request
// and response status code. See [DefaultLogRequestLeveler] for the default level
// determination, which can be customized.
Leveler func(req *http.Request, respStatus int) slog.Level
// Schema defines the mapping of semantic log fields to any custom format, as
// needed by other logging systems.
Schema *LogSchema
// RecoverPanics recovers from panics occurring in the underlying HTTP handlers
// and middleware and returns HTTP 500 (unless status was already sent). Note
// that panics are logged as errors automatically, regardless of this setting.
RecoverPanics bool
// SkipPre can be used to skip logging for a given request. If not provided,
// and not skipped by [LogConfig.SkipPost], all requests are recorded
// (accounting for the provided [LogConfig.Level]). This is a more performant
// alternative to [LogConfig.SkipPost], as it doesn't initialize any
// wrapping of the response writer.
SkipPre func(req *http.Request) bool
// SkipPost can be used to skip logging for a given request, after the response
// has been sent. If not provided, all requests are recorded (accounting for
// the provided [LogConfig.Level]). If provided, true will cause the request to
// not be logged. Use [LogConfig.SkipPost] If you don't need to account for the
// response status code, as it is much more performant.
SkipPost func(req *http.Request, respStatus int) bool
// RequestQuery is a list of query parameters to be logged as attributes. Note
// that if you use query parameters for sensitive data (don't, please), you
// will want to customize this. If not provided, all query parameters will be
// logged. Set to nil or [] to not log any query parameters.
RequestQuery []string
// RequestHeaders is a list of headers to be logged as attributes. If not
// provided, the default is ["Content-Type", "Origin"]. Note that this can
// cause sensitive information to be leaked if not used carefully. Set to "*"
// to log all headers.
RequestHeaders []string
// ResponseHeaders is a list of headers to be logged as attributes. Note that this
// can cause sensitive information to be leaked if not used carefully. Set to "*"
// to log all headers.
ResponseHeaders []string
// RequestBody can be used to control logging of the request body. If not
// provided, bodies will not be logged. Note that this can cause sensitive
// information to be leaked if not used carefully.
RequestBody func(req *http.Request) bool
// ResponseBody can be used to control logging of the response body. If not
// provided, bodies will not be logged. Note that this can cause sensitive
// information to be leaked if not used carefully.
ResponseBody func(req *http.Request) bool
// BodyContentTypes is a list of body Content-Types that can safely be logged.
// Default is "application/json", "application/xml", "text/plain", "text/csv",
// "application/x-www-form-urlencoded" & "".
BodyContentTypes []string
// MaxBodySize defines the maximum length of the body to be logged, in bytes.
// If not provided, defaults to 1KB. Set to -1 to log the entire body.
MaxBodySize int
// AppendAttrs can be used to add extra attributes to the log entry globally.
// Note that this will be called after the request has been processed, and can
// also log sensitive information if not used carefully.
AppendAttrs func(req *http.Request, reqBody string, respStatus int) []slog.Attr
}
func DefaultLogConfig ΒΆ
func DefaultLogConfig() *LogConfig
DefaultLogConfig returns a new LogConfig with the recommended default values.
func (*LogConfig) GetRequestScheme ΒΆ
GetRequestScheme returns the scheme of a given HTTP request.
func (*LogConfig) GetRequestURL ΒΆ
GetRequestURL returns the full request URL, including the scheme, host, path, and query parameters, of a given HTTP request, accounting for items excluded in the logging config.
func (*LogConfig) Validate ΒΆ
Validate validates the log config, and sets the default values for any missing fields, which are required. Use this to validate the config before using it, otherwise UseStructuredLogger will panic if an invalid config is provided.
type LogSchema ΒΆ
type LogSchema struct {
// Base attributes for core logging information.
Timestamp string // Timestamp of the entry. Only applies when registering the schema as a ReplaceAttr handler.
Level string // Log level. Only applies when registering the schema as a ReplaceAttr handler.
Message string // Primary log message. Only applies when registering the schema as a ReplaceAttr handler.
ErrorMessage string // Error message when an error occurs.
Errors string // Multiple errors, as an array.
ErrorType string // Low-cardinality error type (e.g. "ClientAborted", "ValidationError")
ErrorStackTrace string // Stack trace for panic or error
// Source code location attributes for tracking origin of log statements.
SourceFile string // Source file name where the log originated. Only applies when registering the schema as a ReplaceAttr handler.
SourceLine string // Line number in the source file. Only applies when registering the schema as a ReplaceAttr handler.
SourceFunction string // Function name where the log originated. Only applies when registering the schema as a ReplaceAttr handler.
// Request attributes for the incoming HTTP request.
RequestURL string // Full request URL.
RequestMethod string // HTTP method (e.g. GET, POST).
RequestPath string // URL path component.
RequestRemoteIP string // Client IP address.
RequestHost string // Host header value.
RequestScheme string // URL scheme (http, https).
RequestProto string // HTTP protocol version (e.g. HTTP/1.1, HTTP/2).
RequestHeaders string // Selected request headers.
RequestBody string // Request body content, if enabled.
RequestBytes string // Size of request body in bytes.
RequestBytesUnread string // Unread bytes in request body.
RequestUserAgent string // User-Agent header value.
RequestReferer string // Referer header value.
RequestID string // Request ID, if present.
// Response attributes for the HTTP response.
ResponseHeaders string // Selected response headers
ResponseBody string // Response body content, if enabled.
ResponseStatus string // HTTP status code
ResponseDuration string // Request processing duration
ResponseDurationFormat func(key string, duration time.Duration) slog.Attr
ResponseBytes string // Size of response body in bytes
// contains filtered or unexported fields
}
LogSchema defines the mapping of semantic log fields to their corresponding field names in different logging systems and standards. If a field is not provided, it will not be included in the log entry.
Use ">" as a delimiter for objects that should be nested. For example:
- `req>body` & `req>ua`
- becomes: `{"req": {"body": "...", "ua": "..."}}`
func GetLogSchema ΒΆ
func GetLogSchema(id LogSchemaID) (*LogSchema, error)
func MustGetLogSchema ΒΆ
func MustGetLogSchema(id LogSchemaID) *LogSchema
type LogSchemaID ΒΆ
type LogSchemaID string
const ( // LogSchemaSimple represents a simple log schema that works well for local // development, and is also the default schema. LogSchemaSimple LogSchemaID = "simple" // LogSchemaECS represents the Elastic Common Schema (ECS) version 9.0.0. // // Reference: https://www.elastic.co/docs/reference/ecs/ecs-http LogSchemaECS LogSchemaID = "ecs" // LogSchemaLegacy represents the legacy json schema used by chix v1, as close // as possible (some fields missing, e.g. ray_id, country (from Cf-Ipcountry), // "src"). LogSchemaLegacy LogSchemaID = "legacy" )
type M ΒΆ
M is a convenience alias for quickly building a map structure that is going out to a responder. Just a short-hand.
type RealIPConfig ΒΆ
type RealIPConfig struct {
// Trusted is a list of IP addresses or CIDR ranges that are trusted.
Trusted []string
// TrustPrivate is a boolean that indicates if private bogon IP ranges should
// be trusted.
TrustPrivate bool
// TrustAny is a boolean that indicates if any IP should be trusted.
TrustAny bool
// TrustCloudflare is a boolean that indicates if Cloudflare IP ranges should
// be trusted, in addition to their associated headers.
TrustCloudflare bool
// Headers is a list of header parsers that are used to parse the real IP address
// from the request headers. The order here is important. If you have multiple,
// it should be ordered from headers with highest specificity to lowest (i.e.
// headers which only return 1 IP, vs headers like X-Forwarded-For which may
// return multiple IPs). Recommended ordering:
//
// - CF-Connecting-IP
// - X-Real-IP
// - True-Client-IP
// - X-Forwarded-For
Headers []RealIPHeaderParser
// contains filtered or unexported fields
}
RealIPConfig is the configuration for the realip middleware.
func DefaultRealIPConfig ΒΆ
func DefaultRealIPConfig() *RealIPConfig
DefaultRealIPConfig returns a new RealIPConfig with the recommended default values.
func (*RealIPConfig) FromStringOpts ΒΆ
func (c *RealIPConfig) FromStringOpts(options []string) error
FromStringOpts parses a list of string options and updates the config accordingly. See UseRealIPStringOpts for supported options.
func (*RealIPConfig) IsTrusted ΒΆ
func (c *RealIPConfig) IsTrusted(ip net.IP) bool
IsTrusted checks if the given IP is trusted. If [RealIPConfig.TrustAny] is true, this will always return true.
func (*RealIPConfig) Validate ΒΆ
func (c *RealIPConfig) Validate() error
Validate validates the realip config. Use this to validate the config before using it, otherwise UseRealIP will panic if an invalid config is provided.
type RealIPHeaderParser ΒΆ
RealIPHeaderParser is a function that parses the real IP address from the request headers. It returns a list of IP addresses associated with that header (trusted or not).
func RealIPCFConnectingIP ΒΆ
func RealIPCFConnectingIP() RealIPHeaderParser
RealIPCFConnectingIP is a function that parses the Cf-Connecting-Ip header and returns the IP address associated with that header.
func RealIPTrueClientIP ΒΆ
func RealIPTrueClientIP() RealIPHeaderParser
RealIPTrueClientIP is a function that parses the True-Client-Ip header and returns the IP address associated with that header.
func RealIPXForwardedFor ΒΆ
func RealIPXForwardedFor() RealIPHeaderParser
RealIPXForwardedFor is a function that parses the X-Forwarded-For header and returns a list of IP addresses associated with that header, in reverse order.
func RealIPXRealIP ΒΆ
func RealIPXRealIP() RealIPHeaderParser
RealIPXRealIP is a function that parses the X-Real-Ip header and returns the IP address associated with that header.
type RequestDecoder ΒΆ
RequestDecoder is a function that decodes request bodies, url params, etc to the given struct.
func DefaultRequestDecoder ΒΆ
func DefaultRequestDecoder() RequestDecoder
DefaultRequestDecoder returns the default form decoder.
type RequestValidator ΒΆ
RequestValidator is a function that validates a struct.
func DefaultRequestValidator ΒΆ
func DefaultRequestValidator() RequestValidator
DefaultRequestValidator returns the default validator. It supports both Validatable implemented structs, in addition to go-playground/validator struct tags.
type ResolvedError ΒΆ
type ResolvedError struct {
// Err is the final error that will be used, instead of the original error.
// If not provided, the original error will be used.
Err error `json:"error"`
// Errs is a list of errors that contributed to the final error. If this is
// provided directly, it will be used to fill the [Err] field.
Errs []error `json:"errors"`
// StatusCode is the status code that will be used, instead of the original status
// code. If not provided, the original status code will be used. If the status code
// is <500 (and no error resolvers or [ExposableError] implementations are used),
// the error will be marked as public. If this is not desired, you can use [Error]
// directly instead, and provide your own [ResolvedError] with the
// [ResolvedError.Visibility] field set control visibility.
StatusCode int `json:"status_code"`
// Visibility is a flag that indicates the visibility of the error. If [ErrorPublic],
// the error message will be exposed directly to the client. If [ErrorMasked],
// the error message will be masked, and a generic error message will be returned.
Visibility ErrorVisibility `json:"visibility"`
}
ResolvedError is an error that has been resolved (indicating we have some information about if it can be exposed to the client, what the resulting status code may be, etc).
func IsResolvedError ΒΆ
func IsResolvedError(err error) (resolved *ResolvedError, ok bool)
IsResolvedError returns true if the error is a ResolvedError.
func (*ResolvedError) Error ΒΆ
func (e *ResolvedError) Error() string
func (*ResolvedError) LogAttrs ΒΆ
func (e *ResolvedError) LogAttrs() []slog.Attr
LogAttrs returns the attributes that will be added to the log entry for the error.
func (*ResolvedError) Public ΒΆ
func (e *ResolvedError) Public() bool
Public returns true if the error is public. This is calculated in the following order:
- If the [ResolvedError.Visibility] field is set, and is ErrorPublic.
- If the [ResolvedError.Err] field implements the ExposableError interface, and returns true.
- If all of the [ResolvedError.Errs] fields implement the ExposableError interface, and return true.
- If the [ResolvedError.StatusCode] is 1-499 (inclusive).
If none of the above conditions are met, the error will be marked as masked.
func (*ResolvedError) Unwrap ΒΆ
func (e *ResolvedError) Unwrap() []error
type RobotsTextConfig ΒΆ
type RobotsTextConfig struct {
Rules []RobotsTextRule
Sitemaps []string
}
RobotsTextConfig configures the robots.txt middleware.
func (*RobotsTextConfig) String ΒΆ
func (c *RobotsTextConfig) String() string
String returns the robots.txt file as a string.
type RobotsTextRule ΒΆ
type RobotsTextRule struct {
UserAgent string
Allow []string
Disallow []string
CrawlDelay time.Duration
}
RobotsTextRule configures a rule for the robots.txt file.
func (*RobotsTextRule) String ΒΆ
func (r *RobotsTextRule) String() string
String returns the robots.txt rule as a string. Recommended to use RobotsTextConfig.String instead, as it is the full rendered version.
type SecurityTextConfig ΒΆ
type SecurityTextConfig struct {
// Expires is the time when the content of the security.txt file should
// be considered stale (so security researchers should then not trust it).
// Make sure you update this value periodically and keep your file under
// review.
Expires time.Time
// ExpiresIn is similar to Expires, but uses a given timeframe from when
// the http server was started.
ExpiresIn time.Duration
// Contacts contains links or e-mail addresses for people to contact you
// about security issues. Remember to include "https://" for URLs, and
// "mailto:" for e-mails (this will be auto-included if it contains an @
// character).
Contacts []string
// KeyLinks contains links to keys which security researchers should use
// to securely talk to you. Remember to include "https://".
KeyLinks []string
// Languages is a list of language codes that your security team speaks.
Languages []string
// Acknowledgements contains links to webpages where you say thank you
// to security researchers who have helped you. Remember to include
// "https://".
Acknowledgements []string
// Policies contains links to policies detailing what security researchers
// should do when searching for or reporting security issues. Remember
// to include "https://".
Policies []string
// Canonical contains the URLs for accessing your security.txt file. It
// is important to include this if you are digitally signing the
// security.txt file, so that the location of the security.txt file can
// be digitally signed too.
Canonical []string
}
SecurityTextConfig configures the security.txt middleware.
func (*SecurityTextConfig) String ΒΆ
func (h *SecurityTextConfig) String() string
String returns the security.txt file as a string.
type StaticConfig ΒΆ
type StaticConfig struct {
// fs is the filesystem to serve. Note that setting this to anything but an
// embedded filesystem, [os.OpenRoot] should be used.
FS fs.FS
// Prefix is the prefix where the filesystem is mounted on your http router.
Prefix string
// CatchAll is a boolean that determines if [StaticConfig] is being used as a
// catch-all for not-found routes. If so, it will do extra validations for
// using [Error] when the route is related to an API endpoint (see
// [Config.APIBasePath]), as well as enforce specific methods.
CatchAll bool
// AllowLocal is a boolean that, if true, and [StaticConfig.LocalPath] exists,
// it will bypass the provided filesystem and instead use the actual filesystem.
AllowLocal bool
// LocalPath is the subpath to use when [StaticConfig.AllowLocal] is enabled. If
// empty, it will default to [StaticConfig.Path]. It will check for this
// sub-directory in either the current working directory, or the executable
// directory.
LocalPath string
// Path of the embedded filesystem, instead of the entire filesystem. go:embed
// will include the target that gets embedded, as a prefix to the path.
//
// For example, given "go:embed all:public/dist", mounted at "/static", you
// would normally have to access using "/static/public/dist/<etc>". Providing
// path, where path is "public/dist", you can access the same files
// via "/static/<etc>".
Path string
// SPA is a boolean that, if true, will serve a single page application, i.e.
// redirecting all files not found, to the index.html file.
SPA bool
// Fallback is the file to use when a file is not found, and the URI doesn't
// look like it's requesting a static asset. If empty, it will default to
// "index.html".
Fallback string
}
StaticConfig is a net/http.Handler that serves static files from an embedded filesystem. See UseStatic for more information. It also supports serving Single Page Applications (SPA) by redirecting all files not found, to the [StaticConfig.Fallback] file, if configured through [StaticConfig.SPA].
func (*StaticConfig) Validate ΒΆ
func (c *StaticConfig) Validate() error
Validate validates the static config. Use this to validate the config before using it, otherwise UseStatic will panic if an invalid config is provided.
type Validatable ΒΆ
type Validatable interface {
Validate() error
}
Validatable is an interface that can be implemented by structs to provide custom validation logic, on top of the default go-playground/form validation.