web

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package web holds the HTTP plumbing shared by every API handler: the JSON error envelope, request helpers, CSRF and the /api/v1 group.

Index

Constants

View Source
const APIPrefix = "/api/"

APIPrefix is the path prefix whose errors are rendered as JSON.

View Source
const ActorKey = "web.actor"

ActorKey is set on the request context once a guard has loaded a logged-in user, alongside LoggedInKey. It carries just enough of the user for audit logging and per-role field filtering in domain packages that can't import auth (auth imports user, so user can't import auth back without a cycle).

View Source
const DateLayout = "2006-01-02"

DateLayout is the date-only format API inputs use (dates without times, e.g. date of birth or date of event).

View Source
const LoggedInKey = "web.loggedIn"

LoggedInKey is set on the request context once a guard has loaded a logged-in user.

Variables

View Source
var SPARoutes = []string{
	"/",
	"/teams", "/teams/new", "/team/:id", "/team/:id/edit",
	"/news", "/news/new", "/news/:id", "/news/:id/edit",
	"/whatson", "/whatson/new", "/whatson/:id", "/whatson/:id/edit",
	"/gallery", "/documents", "/programmes", "/sponsors", "/players", "/users",
	"/info", "/info/edit", "/contact", "/account", "/reset/:token", "/privacy", "/design",
}

SPARoutes are the React client's routes (client/App.tsx; a test keeps them in step). Any other page path still gets the app, which shows "Page not found", but with a 404 status so crawlers and link checkers see it.

Functions

func BindJSON

func BindJSON(c echo.Context, dst any) error

BindJSON decodes the request body into dst, rejecting unknown fields.

func CSRF

func CSRF(secureCookie bool) echo.MiddlewareFunc

CSRF protects unsafe methods. Browsers that send Sec-Fetch-Site: same-origin pass without a token; other clients must echo the _csrf cookie in X-CSRF-Token. Every failure is a 403.

func ErrorHandler

func ErrorHandler() echo.HTTPErrorHandler

ErrorHandler renders errors on /api/* as the JSON envelope, and every other path as a small HTML page (the web client handles its own pages; this covers redirects, /download and anything else the server answers directly).

func FormBool

func FormBool(c echo.Context, field string) (*bool, error)

FormBool parses an optional boolean form field ("true"/"false"/"1"/"0").

func FormDate

func FormDate(c echo.Context, field string) (*time.Time, error)

FormDate parses an optional YYYY-MM-DD form field.

func FormFile

func FormFile(c echo.Context, field string) (*upload.File, error)

FormFile returns the uploaded file for field, or nil when none was sent.

func FormInt

func FormInt(c echo.Context, field string) (*int, error)

FormInt parses an optional integer form field.

func FormString

func FormString(c echo.Context, field string) *string

FormString returns the form value for field, or nil when the field was not sent at all (as opposed to sent empty).

Unlike echo's own FormParams (which merges the URL query string into request.Form), this reads only the request body: request.PostForm holds urlencoded body values plus, after ParseMultipartForm, the multipart text fields. That keeps a query parameter of the same name from masquerading as a form field, which matters for PATCH's absent-vs-sent semantics (FormBool and FormDate rely on this too, via FormString).

func Health

func Health(c echo.Context) error

Health reports that the server is up.

@Summary	Health check
@Tags		system
@Produce	json
@Success	200	{object}	web.HealthResponse
@Router		/health [get]

func IPExtractor

func IPExtractor(trusted []*net.IPNet) echo.IPExtractor

IPExtractor decides which address c.RealIP() reports. X-Forwarded-For is believed only when the request comes from one of the trusted proxy ranges; otherwise anyone could pick their own IP, dodging the per-IP sign-in limit and faking the address in logs. With no trusted ranges the connecting address is used and the header is ignored.

func IsAppRoute

func IsAppRoute(p string) bool

IsAppRoute reports whether p matches one of SPARoutes; ":name" matches one non-empty path segment.

func LoggedIn

func LoggedIn(c echo.Context) bool

LoggedIn reports whether a guard found a logged-in user for this request.

func MountRedirects

func MountRedirects(e *echo.Echo)

MountRedirects keeps classic-site and /app URLs working now that the web client is served at the root. Only GET and HEAD are redirected. /logout deliberately doesn't sign out: a GET link would let any site sign people out. Signing out is POST /api/v1/auth/logout.

func MountSPA

func MountSPA(e *echo.Echo, files fs.FS, proxy *url.URL)

MountSPA serves the React client at the site root, leaving /api alone. With proxy set (development) every non-API request is reverse-proxied to the Vite dev server, including HMR websockets. Otherwise files (the built client; may be nil) are served: hashed assets, root files, and index.html for page paths (200 for known app routes, 404 otherwise).

func NewAPI

func NewAPI(e *echo.Echo, secureCookies bool) *echo.Group

NewAPI mounts /api and returns the /api/v1 group, protected by CSRF. Unknown /api paths are JSON 404s rather than the web client's not-found page.

func Origin

func Origin(rawURL string) string

Origin returns the scheme and host of rawURL (e.g. the S3 endpoint), or "" when it has none.

func ParamID

func ParamID(c echo.Context, name string) (int, error)

ParamID parses a positive integer path parameter.

func ParseCIDRs

func ParseCIDRs(raw string) ([]*net.IPNet, error)

ParseCIDRs parses a comma-separated list of IP addresses and CIDR ranges, e.g. the TRUSTED_PROXIES setting "10.20.1.10,10.20.1.11" or "10.20.0.0/16". A bare address means just that one host.

func RedactPath

func RedactPath(p string) string

RedactPath replaces a reset token in p with ":token". Other paths are returned unchanged. p may be a site path, an /api/v1 path, or an API path relative to /api/v1 as the client reports it.

func RedactSpanPath

func RedactSpanPath(next echo.HandlerFunc) echo.HandlerFunc

RedactSpanPath overwrites the url.path the tracing middleware recorded when it holds a reset token. Register it after the tracing middleware.

func RequireForm

func RequireForm(c echo.Context) error

RequireForm rejects a request whose Content-Type isn't a form: without it, web.FormString and friends silently return nil for a JSON (or any other) body, so a write with the wrong Content-Type would look like "no fields sent" and succeed doing nothing instead of failing loudly. Handlers that read multipart or urlencoded form fields must call this first.

func SecurityHeaders

func SecurityHeaders(hsts, csp bool, fileOrigin string) echo.MiddlewareFunc

SecurityHeaders sets the browser protections on every response. hsts is for sites served only over HTTPS. csp is off in development, where the Vite dev server needs inline scripts and websockets; the Swagger UI under /api/v1/swagger never gets it, for the same reason. fileOrigin is where uploaded files are served from (see Origin).

Types

type APIError

type APIError struct {
	Code    int               `json:"code"`
	Message string            `json:"message"`
	Fields  map[string]string `json:"fields,omitempty"`
}

APIError is the body of every API error response.

type Actor

type Actor struct {
	ID    int
	Email string
	Role  role.Role
	// TeamID is the team a Manager manages; zero for other roles.
	TeamID int
}

Actor is the logged-in user making a request.

func CurrentActor

func CurrentActor(c echo.Context) (Actor, bool)

CurrentActor returns the acting user for this request, set by a guard in the auth package once a session is loaded.

type ErrorResponse

type ErrorResponse struct {
	Error APIError `json:"error"`
}

ErrorResponse wraps APIError as {"error": {...}}.

type Guards

type Guards struct {
	Login               echo.MiddlewareFunc // any logged-in user
	Editor              echo.MiddlewareFunc // logged in, not Manager or Photographer
	NotManager          echo.MiddlewareFunc // logged in, not Manager (gallery)
	Players             echo.MiddlewareFunc // logged in, an editor but not Programme Editor
	ClubSecretaryHigher echo.MiddlewareFunc // Safeguarding Officer, Club Secretary, Chairperson, Webmaster
	Identify            echo.MiddlewareFunc // loads the user if logged in; never rejects
}

Guards are the authorisation middlewares handlers attach to routes. They are built by the auth package; web only defines the shape so domain packages don't import auth.

type HealthResponse

type HealthResponse struct {
	Status string `json:"status"`
}

HealthResponse is the body of GET /health.

Directories

Path Synopsis
Package apitest drives the API in handler tests the way a same-origin browser would.
Package apitest drives the API in handler tests the way a same-origin browser would.

Jump to

Keyboard shortcuts

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