Documentation
¶
Overview ¶
Package hanami is a pure-Go (no cgo) reimplementation of the deterministic core of the Ruby Hanami framework — the Router (hanami-router) and the Action lifecycle (hanami-controller) — matching MRI's `hanami-router` and `hanami-controller` 2.x observable behaviour, without any Ruby runtime.
It builds a fast segment-trie router with the full recognition surface — verb helpers (get/post/put/patch/delete/…), the root route, named routes (`as:`) with path/URL helpers, path parameters (`/books/:id`), globbing (`*rest`), per-parameter regexp constraints, nested scopes, redirects and mounted Rack apps — and dispatches a matched request to a resolved endpoint. On top of it, Action runs the request/response lifecycle: `before`/`after` callbacks, `halt`, `redirect_to`, status/body/format/header setters, content negotiation, cookies/flash/session accessors and exception handling.
The library reuses github.com/go-ruby-rack/rack for the Rack env, request, response, headers and parameter model — this package never touches the network. Two things are explicit seams, supplied by the host:
- the endpoint Resolver, mapping a `to:` string ("books.index") to a callable RackApp; and
- the action body ActionCall, the Ruby `handle(request, response)` method, which reads the Request and mutates the Response.
This is the v0.1 foundation for a later rbgo binding. The full app / slices / container boot, hanami-view rendering, dry-validation params contracts, assets, the CLI/generators and the settings/providers system are deferred — see the README roadmap.
Index ¶
- Constants
- type Action
- type ActionCall
- type ActionOption
- func Accept(formats ...string) ActionOption
- func After(cbs ...Callback) ActionOption
- func Before(cbs ...Callback) ActionOption
- func HandleException(hs ...ExceptionHandler) ActionOption
- func WithDefaultFormat(format string) ActionOption
- func WithDefaultStatus(status int) ActionOption
- func WithParamsValidator(v ParamsValidator) ActionOption
- func WithSessionLoader(l SessionLoader) ActionOption
- type Callback
- type ExceptionHandler
- type Flash
- type ParamsValidator
- type RackApp
- type RackResponse
- type Request
- func (r *Request) Accepts(format string) bool
- func (r *Request) Cookies() *rack.Params
- func (r *Request) Flash() *Flash
- func (r *Request) Format() string
- func (r *Request) Param(key string) string
- func (r *Request) Params() *rack.Params
- func (r *Request) ParamsError() error
- func (r *Request) ParamsValid() bool
- func (r *Request) Session() map[string]any
- type Resolver
- type Response
- func (r *Response) Body() string
- func (r *Response) DeleteCookie(key string, value rack.CookieValue)
- func (r *Response) Flash() *Flash
- func (r *Response) Format() string
- func (r *Response) GetHeader(key string) any
- func (r *Response) Halt(status int, body string)
- func (r *Response) Headers() *rack.Headers
- func (r *Response) RedirectTo(url string, status int)
- func (r *Response) Session() map[string]any
- func (r *Response) SetBody(body string)
- func (r *Response) SetCookie(key string, value rack.CookieValue)
- func (r *Response) SetFormat(format string)
- func (r *Response) SetHeader(key string, value any)
- func (r *Response) SetStatus(status int)
- func (r *Response) Status() int
- func (r *Response) Write(chunk string)
- type Route
- type RouteOption
- type Router
- func (rt *Router) Call(env rack.Env) RackResponse
- func (rt *Router) Delete(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Get(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Link(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Mount(prefix string, app RackApp)
- func (rt *Router) Options(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Patch(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Path(name string, params map[string]string) (string, error)
- func (rt *Router) Post(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Put(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) Redirect(path, target string, status int, opts ...RouteOption) *Route
- func (rt *Router) Root(to To, opts ...RouteOption) *Route
- func (rt *Router) Routes() []*Route
- func (rt *Router) Scope(prefix string, fn func())
- func (rt *Router) Trace(path string, to To, opts ...RouteOption) *Route
- func (rt *Router) URL(name string, params map[string]string) (string, error)
- func (rt *Router) Unlink(path string, to To, opts ...RouteOption) *Route
- type RouterOption
- type SessionLoader
- type To
Constants ¶
const RouterParams = "router.params"
RouterParams is the env key under which Call stores the matched path params (Hanami's router.params), read by Action to build request params.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶
type Action struct {
// contains filtered or unexported fields
}
Action is a pure-Go port of the Hanami::Action lifecycle: it builds a Request/Response over Rack, runs content negotiation, `before` callbacks, the ActionCall body, exception handling and `after` callbacks, honouring `halt`/`redirect_to`, then finalises the Rack tuple. It is a RackApp via Action.Call.
func NewAction ¶
func NewAction(name string, handle ActionCall, opts ...ActionOption) *Action
NewAction builds an action named name whose body is handle.
type ActionCall ¶
ActionCall is the action business body — the Ruby `handle(request, response)` method as a Go seam. It receives the action name, the built Request and the Response to mutate, and returns an error to trigger exception handling. This is the single seam a later rbgo binding plugs the Ruby action into.
type ActionOption ¶
type ActionOption func(*Action)
ActionOption configures an Action.
func Accept ¶
func Accept(formats ...string) ActionOption
Accept restricts the action to the given formats; a request that accepts none of them is answered 406 Not Acceptable (Hanami's `format`/`accept`).
func HandleException ¶
func HandleException(hs ...ExceptionHandler) ActionOption
HandleException registers exception handlers, tried in registration order.
func WithDefaultFormat ¶
func WithDefaultFormat(format string) ActionOption
WithDefaultFormat sets the initial response format (e.g. "json").
func WithDefaultStatus ¶
func WithDefaultStatus(status int) ActionOption
WithDefaultStatus sets the initial response status (default 200).
func WithParamsValidator ¶
func WithParamsValidator(v ParamsValidator) ActionOption
WithParamsValidator sets the params-validation seam.
func WithSessionLoader ¶
func WithSessionLoader(l SessionLoader) ActionOption
WithSessionLoader sets the session-store seam.
type Callback ¶
Callback is a before/after hook (Hanami's `before`/`after`). It may read the request and mutate the response, and may call Response.Halt to short-circuit.
type ExceptionHandler ¶
ExceptionHandler handles an error raised by the action body (Hanami's `handle_exception`). It returns true when it has handled the error (having set the response); the first handler to return true wins. When none handles it, the action responds 500.
type Flash ¶
type Flash struct {
// contains filtered or unexported fields
}
Flash is Hanami's flash: a two-generation message store. Values set this request are readable next request; values carried in from last request are readable now and swept after the response is built.
func (*Flash) Get ¶
Get reads a value from the current generation, falling back to the value just set for the next request.
type ParamsValidator ¶
ParamsValidator is the params-validation seam (Hanami's params contract). It receives the raw merged params and returns the validated params and an error. A nil validator passes the raw params through unchanged.
type RackApp ¶
type RackApp func(env rack.Env) RackResponse
RackApp is a Rack application: it maps a Rack rack.Env to a response tuple. It is the callable an endpoint resolves to, and the shape a mounted app must have. A Router and an Action are both RackApps via their Call method.
type RackResponse ¶
RackResponse is the SPEC `[status, headers, body]` tuple in struct form. It is what Router.Call and Action.Call return; use RackResponse.ToTuple to get the three plain values.
type Request ¶
Request is Hanami::Action::Request: a thin layer over rack.Request that adds the merged params (path + query + body), content negotiation, and session, cookie and flash accessors. It is built by Action.Call and handed to the action body and callbacks.
func (*Request) Accepts ¶
Accepts reports whether the request's Accept header accepts the given short format (or "*/*" wildcard), matching Action's content negotiation.
func (*Request) Format ¶
Format returns the negotiated short format name (e.g. "json", "html") derived from the request CONTENT_TYPE then the Accept header, or "" when neither maps to a known format.
func (*Request) Param ¶
Param returns the string value of a single param, or "" if absent or non-string, a convenience over Request.Params.
func (*Request) ParamsError ¶
ParamsError returns the validator's error, or nil when the params are valid.
func (*Request) ParamsValid ¶
ParamsValid reports whether the params validator (if any) accepted the input. A request with no validator is always valid.
type Resolver ¶
Resolver maps a `to:` endpoint name (e.g. "books.index") to a RackApp. It is the host seam by which action names become callables. It returns false when the name is unknown, which the router reports as a 404. A router with no resolver treats every string endpoint as unresolved.
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response is Hanami::Action::Response: a mutable response the action body and callbacks build up — status, body, headers, format, cookies, session and flash — finalised to a Rack tuple by Action.Call. Reuses rack.Response and rack.Headers for finishing (content-length, cookie encoding).
func (*Response) DeleteCookie ¶
func (r *Response) DeleteCookie(key string, value rack.CookieValue)
DeleteCookie schedules an expiring Set-Cookie for key at finish.
func (*Response) Halt ¶
Halt sets the status and body and unwinds the lifecycle immediately, matching Hanami's `halt`. A zero or empty body defaults to the status' reason phrase.
func (*Response) RedirectTo ¶
RedirectTo sets a redirect to url with the given status (default 302) and halts the lifecycle, matching Hanami's `redirect_to`.
func (*Response) SetCookie ¶
func (r *Response) SetCookie(key string, value rack.CookieValue)
SetCookie schedules a Set-Cookie for key with the given value at finish (Hanami's `response.cookies[key]=`).
func (*Response) SetFormat ¶
SetFormat sets the response format, which selects the content-type at finish (Hanami's `response.format=`). An unknown format leaves the content-type unset.
type Route ¶
type Route struct {
Method string
Pattern string
Name string
// contains filtered or unexported fields
}
Route is a single declared route: a method, the full path pattern (including any scope prefix), its parsed segments, the target endpoint and an optional name for the path/URL helpers.
type RouteOption ¶
type RouteOption func(*routeOptions)
RouteOption configures a single route declaration (`as:`, `constraints:`).
func As ¶
func As(name string) RouteOption
As names the route for the path/URL helpers (Hanami's `as:`).
func Constraints ¶
func Constraints(c map[string]string) RouteOption
Constraints attaches per-parameter regexp constraints (Hanami's `constraints:`). Each value is an un-anchored regexp matched against the whole segment.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router is a pure-Go port of Hanami::Router: a segment-trie of routes with verb helpers, named path/URL helpers, params, constraints, scopes, redirects and mounts. Build it with NewRouter, declare routes with the verb methods, and dispatch with Router.Call. It is itself a RackApp.
func NewRouter ¶
func NewRouter(opts ...RouterOption) *Router
NewRouter builds an empty Router. Pass WithResolver and/or WithBase, then declare routes.
func (*Router) Call ¶
func (rt *Router) Call(env rack.Env) RackResponse
Call matches env's method and PATH_INFO and dispatches to the resolved endpoint, returning 404 when nothing matches the path and 405 (with an Allow header) when the path matches but the method does not. HEAD falls back to a GET route, matching Hanami. It is the RackApp entry point.
func (*Router) Get ¶
func (rt *Router) Get(path string, to To, opts ...RouteOption) *Route
Verb helpers. Each declares a route for its HTTP method.
func (*Router) Mount ¶
Mount attaches a Rack app at a prefix. Requests whose path is the prefix or begins with "prefix/" are dispatched to app with SCRIPT_NAME/PATH_INFO adjusted (the prefix is moved into SCRIPT_NAME), matching Hanami's `mount`. Mounts are matched for any HTTP method, longest prefix first.
func (*Router) Path ¶
Path builds the path for the named route, substituting params into its dynamic and glob segments and appending any leftover params as a sorted query string, matching Hanami's `routes.path(:name, **params)`. It errors on an unknown name or a missing required parameter.
func (*Router) Redirect ¶
func (rt *Router) Redirect(path, target string, status int, opts ...RouteOption) *Route
Redirect declares a route that responds with a redirect to target. The default status is 301 (Hanami's `redirect` default).
func (*Router) Root ¶
func (rt *Router) Root(to To, opts ...RouteOption) *Route
Root declares the GET "/" route, named :root, matching Hanami's `root`.
func (*Router) URL ¶
URL builds the absolute URL for the named route, prefixing Router.Path with the configured scheme and host, matching Hanami's `routes.url(:name, …)`.
type RouterOption ¶
type RouterOption func(*Router)
RouterOption configures a Router at construction.
func WithBase ¶
func WithBase(scheme, host string) RouterOption
WithBase sets the scheme and host used by Router.URL (default "http", "localhost").
func WithResolver ¶
func WithResolver(r Resolver) RouterOption
WithResolver sets the endpoint Resolver.
type SessionLoader ¶
SessionLoader loads the session map for a request (the session-store seam). A nil loader reads env["rack.session"] when it is a map[string]any.
type To ¶
type To struct {
// contains filtered or unexported fields
}
To is the `to:` argument of a route declaration. Build it with ToName (an endpoint name resolved by the router's Resolver), ToApp (a Rack callable) or ToAction (a Action).
