Avatar Ilya Mateyko

go.astrophena.name/base Module

GitHub repository | Commit (49382e9)

Base Go packages for my projects.

package web

import "go.astrophena.name/base/web"

Package web is a collection of functions and types for building web services.

Index

Variables

var StaticFS = hashfs.NewFS(staticFS)

StaticFS is a hashfs.FS containing the base static resources (like default CSS) served by the Server under the "/static/" path prefix.

If you provide a custom [Server.StaticFS], you must use the Server.StaticHashName method to generate correct hashed URLs for all static assets (both embedded and custom).

Functions

func IsTrustedRequest

func IsTrustedRequest(r *http.Request) bool

IsTrustedRequest reports whether r is a trusted request. A trusted request, when resulting in an error handled by RespondError, will have its underlying error message exposed to the client in the HTML response.

func RespondError

func RespondError(w http.ResponseWriter, r *http.Request, err error)

RespondError writes an error response in HTML format to w and logs the error using logger.Logf from context's environment (cli.Env) if error is ErrInternalServerError.

If the error is a StatusErr or wraps it, it extracts the HTTP status code and sets the response status code accordingly. Otherwise, it sets the response status code to http.StatusInternalServerError.

If the request is marked as trusted (see IsTrustedRequest and TrustRequest), the original error message will be included in the HTML response. This is useful for debugging by service administrators.

You can wrap any error with fmt.Errorf to create a StatusErr and set a specific HTTP status code:

// This will set the status code to 404 (Not Found).
web.RespondError(w, r, fmt.Errorf("resource %w", web.ErrNotFound))

func RespondJSON

func RespondJSON(w http.ResponseWriter, response any)

RespondJSON marshals the provided response object as JSON and writes it to the http.ResponseWriter. It sets the Content-Type header to application/json before marshalling. In case of marshalling errors, it writes an internal server error with the error message.

func RespondJSONError

func RespondJSONError(w http.ResponseWriter, r *http.Request, err error)

RespondJSONError writes an error response in JSON format to w and logs the error using logger.Logf from context's environment (cli.Env) if error is ErrInternalServerError.

If the error is a StatusErr or wraps it, it extracts the HTTP status code and sets the response status code accordingly. Otherwise, it sets the response status code to http.StatusInternalServerError. The error message is always included in the JSON response.

You can wrap any error with fmt.Errorf to create a StatusErr and set a specific HTTP status code:

// This will set the status code to 404 (Not Found).
web.RespondJSONError(w, r, fmt.Errorf("resource %w", web.ErrNotFound))

func TrustRequest

func TrustRequest(r *http.Request) *http.Request

TrustRequest marks r as a trusted request and returns a new request with the trusted status embedded in its context. This function should typically be used for requests originating from service administrators or other privileged users.

Types

type CheckResponse

type CheckResponse struct {
	Status string `json:"status"`
	OK     bool   `json:"ok"`
}

CheckResponse represents a status of an individual check.

type DebugHandler

type DebugHandler struct {
	// contains filtered or unexported fields
}

DebugHandler is an http.Handler that serves a debugging "homepage", and provides helpers to register more debug endpoints and reports.

The rendered page consists of three sections: header menu, informational key/value pairs and links to other pages.

Callers can add to these sections using the MenuFunc, KV and Link helpers respectively.

Additionally, the Handle method offers a shorthand for correctly registering debug handlers and cross-linking them from /debug/.

Methods of DebugHandler can be safely called by multiple goroutines.

func Debugger

func Debugger(mux *http.ServeMux) *DebugHandler

Debugger returns the DebugHandler registered on mux at /debug/, creating it if necessary.

func (*DebugHandler) Handle

func (d *DebugHandler) Handle(slug, desc string, handler http.Handler)

Handle registers handler at /debug/<slug> and creates a descriptive entry in /debug/ for it.

func (*DebugHandler) HandleFunc

func (d *DebugHandler) HandleFunc(slug, desc string, handler http.HandlerFunc)

HandleFunc is like Handle, but accepts http.HandlerFunc instead of http.Handler.

func (*DebugHandler) KV

func (d *DebugHandler) KV(k string, v any)

KV adds a key/value list item to /debug/.

func (*DebugHandler) KVFunc

func (d *DebugHandler) KVFunc(k string, v func() any)

KVFunc adds a key/value list item to /debug/. v is called on every render of /debug/.

func (d *DebugHandler) Link(url, desc string)

Link adds a URL and description list item to /debug/.

func (*DebugHandler) MenuFunc

func (d *DebugHandler) MenuFunc(f func(*http.Request) []MenuItem)

MenuFunc sets a function that generates custom menu items for /debug/ page header.

func (*DebugHandler) ServeHTTP

func (d *DebugHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface.

type HTMLItem

type HTMLItem string

HTMLItem is a MenuItem that can contain arbitrary HTML.

func (HTMLItem) ToHTML

func (hi HTMLItem) ToHTML() template.HTML

type HealthFunc

type HealthFunc func() (status string, ok bool)

HealthFunc is the health check function that reports the state of a particular subsystem.

type HealthHandler

type HealthHandler struct {
	// contains filtered or unexported fields
}

HealthHandler is an HTTP handler that returns information about the health status of the running service.

func Health

func Health(mux *http.ServeMux) *HealthHandler

Health returns the HealthHandler registered on mux at /health, creating it if necessary.

func (*HealthHandler) RegisterFunc

func (h *HealthHandler) RegisterFunc(name string, f HealthFunc)

RegisterFunc registers the health check function by the given name. If the health check function with this name already exists, RegisterFunc panics.

Health check function must be safe for concurrent use.

func (*HealthHandler) ServeHTTP

func (h *HealthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface.

type HealthResponse

type HealthResponse struct {
	OK     bool                     `json:"ok"`
	Checks map[string]CheckResponse `json:"checks"`
}

HealthResponse represents a response of the /health endpoint.

type LinkItem

type LinkItem struct {
	Name   string
	Target string
}

LinkItem is a MenuItem that is a link.

func (LinkItem) ToHTML

func (li LinkItem) ToHTML() template.HTML
type MenuItem interface {
	ToHTML() template.HTML
}

MenuItem is a debug page header menu item.

type Middleware

type Middleware func(http.Handler) http.Handler

type Server

type Server struct {
	// Mux is a http.ServeMux to serve.
	Mux *http.ServeMux
	// Debuggable specifies whether to register debug handlers at /debug/.
	Debuggable bool
	// Middleware specifies an optional slice of HTTP middleware that's applied to
	// each request.
	Middleware []Middleware
	// Addr is a network address to listen on (in the form of "host:port").
	Addr string
	// Ready specifies an optional function to be called when the server is ready
	// to serve requests.
	Ready func()
	// StaticFS specifies an optional filesystem containing static assets (like CSS,
	// JS, images) to be served. If provided, it's combined with the embedded
	// StaticFS and served under the "/static/" path prefix.
	// Files in this FS take precedence over the embedded ones if names conflict.
	StaticFS fs.FS
	// contains filtered or unexported fields
}

Server is used to configure the HTTP server started by Server.ListenAndServe.

All fields of Server can't be modified after Server.StaticHashName, Server.ListenAndServe or Server.ServeHTTP is called for a first time.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe starts the HTTP server that can be stopped by canceling ctx.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface.

func (*Server) StaticHashName

func (s *Server) StaticHashName(name string) string

StaticHashName returns the cache-busting hashed name for a static file path. If the path exists, its hashed name is returned. Otherwise, the original name is returned.

type StatusErr

type StatusErr int

StatusErr is a sentinel error type used to represent HTTP status code errors.

const (
	// ErrBadRequest represents a bad request error (HTTP 400).
	ErrBadRequest StatusErr = http.StatusBadRequest
	// ErrUnauthorized represents an unauthorized access error (HTTP 401).
	ErrUnauthorized StatusErr = http.StatusUnauthorized
	// ErrForbidden represents a forbidden access error (HTTP 403).
	ErrForbidden StatusErr = http.StatusForbidden
	// ErrNotFound represents a not found error (HTTP 404).
	ErrNotFound StatusErr = http.StatusNotFound
	// ErrMethodNotAllowed represents a method not allowed error (HTTP 405).
	ErrMethodNotAllowed StatusErr = http.StatusMethodNotAllowed
	// ErrInternalServerError represents an internal server error (HTTP 500).
	ErrInternalServerError StatusErr = http.StatusInternalServerError
)

func (StatusErr) Error

func (se StatusErr) Error() string

Error implements the error interface. It returns a lowercase representation of the HTTP status text for the wrapped code.