Documentation
¶
Overview ¶
Package grape is a pure-Go (no cgo) reimplementation of the deterministic, interpreter-independent core of Ruby's Grape REST-API framework (the `grape` gem): route modelling + matching, params validation/coercion, and response formatting.
It is the API-machinery backend for go-embedded-ruby, but is a standalone, reusable module with no dependency on the Ruby runtime — a sibling of go-ruby-rack. Three deterministic pieces live here:
- A Router: add routes (get/post/…, path patterns with :params, .:format suffixes and *wildcards, namespaces, versioning) and resolve (method, path, headers) → (matched route, path params) plus the 404 / 405 / 406 decisions.
- A ParamsValidator: turn a params declaration (requires/optional, type coercion, values, length, regexp, mutual-exclusion, defaults, nested groups) plus raw params into the coerced params hash or a ValidationErrors carrying Grape's exact messages.
- A Formatter: json / txt / xml serialisation of the response value shape.
Binding endpoint blocks to live Ruby objects and parsing the Rack env are the host's job (rbgo, tied to go-ruby-rack); this library hands back a small, explicit value model the host maps to and from its own objects.
Index ¶
- func DefaultStatus(method string) int
- func MimeFor(format string) string
- func Negotiate(extFormat, forced, accept string, offered []string) (string, bool)
- func NotFoundBody() (int, string)
- type ErrorBody
- type Formatter
- type Match
- type MatchStatus
- type OrderedMap
- type Param
- type ParamSet
- type ParamsValidator
- type Raw
- type Regexp
- type Response
- type Route
- type Router
- func (rt *Router) Add(r *Route)
- func (rt *Router) Delete(pattern string, h any) *Route
- func (rt *Router) Get(pattern string, h any) *Route
- func (rt *Router) Head(pattern string, h any) *Route
- func (rt *Router) Match(method, path string) Match
- func (rt *Router) Patch(pattern string, h any) *Route
- func (rt *Router) Post(pattern string, h any) *Route
- func (rt *Router) Put(pattern string, h any) *Route
- func (rt *Router) Routes() []*Route
- type Type
- type ValidationError
- type ValidationErrors
- type Version
- type VersionStrategy
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultStatus ¶
DefaultStatus returns the status Grape assigns to a method when the endpoint does not set one explicitly: 201 for POST, 200 otherwise. HEAD mirrors GET.
func MimeFor ¶
MimeFor returns the MIME type Grape emits for a format symbol, or "" if the format is unknown.
func Negotiate ¶
Negotiate resolves the response format for a request. It applies Grape's precedence: an explicit ".:format" path extension (extFormat, may be "") wins; otherwise a forced API-wide format (forced, may be "") wins; otherwise the Accept header is matched against the API's offered formats. offered lists the format symbols the API serves, in preference order.
It returns the chosen format and true, or ("", false) when the request cannot be satisfied — the 406 Not Acceptable decision.
func NotFoundBody ¶
NotFoundBody / MethodNotAllowedBody / NotAcceptableBody produce the plain bodies Grape returns for the routing failures. Grape returns a bare "404 Not Found" text for 404 and a JSON error for 405/406 under a JSON API.
Types ¶
type ErrorBody ¶
type ErrorBody struct {
Message any // string, or a structured value for error!(hash, status)
Status int
}
ErrorBody is the value Grape serialises for an error! / a raised failure: a single "error" key (plus optional detail). It is emitted through the same Formatter as a normal response.
func MethodNotAllowedBody ¶
MethodNotAllowedBody returns the 405 status and the value Grape serialises ({"error":"405 Not Allowed"}).
func NotAcceptableBody ¶
NotAcceptableBody returns the 406 status and error value.
func ValidationErrorBody ¶
func ValidationErrorBody(v *ValidationErrors) ErrorBody
ValidationErrorBody shapes a *ValidationErrors into the 400 body Grape returns: {"error":"<joined messages>"}. The status is always 400.
type Formatter ¶
type Formatter struct{}
Formatter serialises a response value to the wire form for a format symbol. The value model is the generic Go tree the host produces from the endpoint's return value: nil, bool, integers, floats, string, []any, and map[string]any (or *OrderedMap for order-preserving hashes). Binding a live Ruby object to this tree is the host's job; the formatter only serialises the tree.
func (Formatter) Format ¶
Format serialises v for the given format symbol ("json", "txt", "xml"). It returns the body and the Content-Type MIME. An unknown format is an error.
func (Formatter) JSON ¶
JSON renders v as compact JSON, matching Grape's default (MultiJson) output: no spaces, sorted keys for plain maps, insertion order for OrderedMap.
func (Formatter) Txt ¶
Txt renders v the way Grape's Txt formatter does: a String is emitted verbatim, anything else via its to_s form. For the generic tree that is a JSON-free inspection; the host may supply richer to_s via the value already being a string. Here a string passes through and other values use a Go string form.
type Match ¶
type Match struct {
Status MatchStatus
Route *Route
Params map[string]string
Allowed []string
}
Match resolves a request. On StatusOK, Route and Params are the matched route and its captured path params. On StatusMethodNotAllowed, Allowed lists the methods the path does accept (for the Allow header). GET implicitly satisfies a HEAD request (Grape/Rack semantics).
type MatchStatus ¶
type MatchStatus int
MatchStatus is the routing decision for a request.
const ( // StatusOK: a route matched both method and path. StatusOK MatchStatus = iota // StatusNotFound (404): no route's path matched. StatusNotFound // StatusMethodNotAllowed (405): the path matched at least one route but not // for the request method. StatusMethodNotAllowed )
type OrderedMap ¶
type OrderedMap struct {
// contains filtered or unexported fields
}
OrderedMap is an insertion-ordered string-keyed map, so a hash's key order survives JSON/XML serialisation (a plain map[string]any is emitted in sorted key order for determinism).
func (*OrderedMap) Get ¶
func (m *OrderedMap) Get(key string) (any, bool)
Get returns the value for key.
func (*OrderedMap) Keys ¶
func (m *OrderedMap) Keys() []string
Keys returns the keys in insertion order.
func (*OrderedMap) Set ¶
func (m *OrderedMap) Set(key string, val any)
Set inserts or updates a key, preserving first-insertion order.
type Param ¶
type Param struct {
Name string
Required bool // requires vs optional
Type Type // scalar type; "" means untyped (raw string passthrough)
ElemType Type // element type for Array[T]; "" for a bare Array
IsArray bool // type: Array or Array[T]
IsHash bool // type: Hash (a nested group container)
// Values / ExceptValues constrain the coerced value. A value list may be an
// explicit set (Values) or an inclusive integer range (RangeMin..RangeMax
// when HasRange is set).
Values []any
ExceptValues []any
HasRange bool
RangeMin int64
RangeMax int64
// Length constraints (String/Array). Present flags gate each bound.
HasMinLen bool
MinLen int
HasMaxLen bool
MaxLen int
Regexp Regexp // regexp: /…/ — matched via the injected matcher
AllowBlank *bool // allow_blank: false rejects "" / whitespace; nil = default true
// Default supplies a value when the param is absent. If DefaultFunc is set it
// is called lazily (callable default); otherwise Default is used verbatim.
HasDefault bool
Default any
DefaultFunc func() any
// CoerceWith replaces built-in coercion with a host lambda; it receives the
// raw string and returns the coerced value (and false to signal invalid).
CoerceWith func(raw string) (any, bool)
// Group holds the nested declarations of a Hash param (`requires :g, type:
// Hash do … end`), including its own cross-parameter validators, so nested
// exclusivity reports names as "grp[a], grp[b]".
Group *ParamSet
}
Param is one declared parameter in a `params do … end` block. It mirrors the options a `requires`/`optional` line carries. The host builds these from the Ruby DSL; the validator consumes them.
type ParamSet ¶
type ParamSet struct {
Params []*Param
MutuallyExclusive [][]string
ExactlyOneOf [][]string
AtLeastOneOf [][]string
AllOrNoneOf [][]string
}
ParamSet is a full `params do … end` declaration plus the cross-parameter group validators (mutually_exclusive and friends).
type ParamsValidator ¶
type ParamsValidator struct {
// contains filtered or unexported fields
}
ParamsValidator validates and coerces raw request params against a ParamSet.
func NewParamsValidator ¶
func NewParamsValidator(set *ParamSet) *ParamsValidator
NewParamsValidator builds a validator for a declaration.
func (*ParamsValidator) Validate ¶
func (v *ParamsValidator) Validate(raw Raw) (map[string]any, *ValidationErrors)
Validate coerces raw against the declaration. On success it returns the coerced params map and nil. On failure it returns the partially-coerced map and a *ValidationErrors carrying every failure in declaration order — the same order (and messages) Grape renders into its 400 body.
type Raw ¶
Raw is the request parameter tree the host hands in. A leaf is a string; a nested Hash param is a map[string]any; an array is a []any of strings (or of nested maps for Array-of-Hash). This mirrors what Rack parses from a query / form / JSON body.
type Regexp ¶
type Regexp struct {
Source string // the pattern source, for diagnostics
Match func(s string) bool // returns true when s matches
}
Regexp is a compiled-pattern reference. The deterministic core does not embed a regexp engine (that is go-ruby-regexp's job); the host supplies a Match function. A zero Regexp (Match nil) means "no regexp constraint".
type Response ¶
Response is the shaped result of an endpoint: an HTTP status, a value to serialise, and the negotiated format. The host runs the endpoint body (that is the seam) and hands the outcome here to be shaped into a body via a Formatter.
type Route ¶
type Route struct {
Method string // upper-case HTTP verb ("GET", "POST", …); "" or "*" matches any
Pattern string // the raw declared pattern, e.g. "/users/:id"
// Handler is an opaque host reference to the endpoint body. The router never
// runs it; it is handed back on a match so the host (rbgo) can invoke it.
Handler any
// contains filtered or unexported fields
}
Route is a single Grape endpoint: an HTTP method plus a compiled path pattern. A pattern is a slash-separated list of segments; a segment may be a literal, a named capture (":name"), or a trailing wildcard ("*name") that greedily swallows the remainder of the path. A ".:format" suffix on the final segment binds the request extension (e.g. "/users/:id.:format").
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router holds an ordered set of routes and resolves a request to a match. Route order is significant: the first route whose method and path both match wins, mirroring Grape's first-declared-first-served dispatch.
func (*Router) Get ¶
Get/Post/Put/Patch/Delete/Head add a route for the corresponding verb and return it, so a handler can be attached fluently.
type Type ¶
type Type string
Type names the coercion targets Grape's params DSL understands. A scalar type coerces a single raw string; Array[T] / Hash coerce collections (handled in validate.go via ElemType).
type ValidationError ¶
type ValidationError struct {
Param string // e.g. "id" or "grp[inner]"
Message string // e.g. "is missing", "is invalid"
}
ValidationError is a single parameter failure: the fully-qualified parameter name (nested groups joined as "group[inner]") plus the message fragment Grape emits for it (without the parameter prefix).
func (ValidationError) Error ¶
func (e ValidationError) Error() string
Error renders the failure the way Grape does: "<param> <message>".
type ValidationErrors ¶
type ValidationErrors struct {
Errors []ValidationError
}
ValidationErrors is the aggregate raised as Grape::Exceptions::ValidationErrors. Its Error() string is the comma-joined per-parameter messages, matching the body Grape returns for a 400 (`{"error":"id is missing, name is invalid"}`).
func (*ValidationErrors) Empty ¶
func (v *ValidationErrors) Empty() bool
Empty reports whether any error was collected.
func (*ValidationErrors) Error ¶
func (v *ValidationErrors) Error() string
Error joins the individual messages with ", " in declaration order.
type Version ¶
type Version struct {
Name string // the version string, e.g. "v1"
Strategy VersionStrategy
Vendor string // vendor for VersionHeader (application/vnd.<vendor>-<name>+<fmt>)
Param string // parameter name for VersionParam (default "apiver")
}
Version describes an API's versioning configuration.
func (*Version) Matches ¶
Matches reports whether a request carries this version. path is the raw request path (only consulted for VersionPath), accept is the Accept header, and param is the version parameter value (only consulted for VersionParam / when set). For VersionPath the caller strips the matched prefix separately via Prefix.
type VersionStrategy ¶
type VersionStrategy int
VersionStrategy names how Grape locates the requested API version.
const ( // VersionPath: the version is the first path segment ("/v1/…"). VersionPath VersionStrategy = iota // VersionHeader: the version is read from an Accept header vendor tree, // e.g. "Accept: application/vnd.vendor-v1+json". VersionHeader // VersionParam: the version is a query/body parameter (default name "apiver"). VersionParam // VersionAccept: the version is the whole Accept media-type parameter // ("Accept: application/json; version=v1"), less common than VersionHeader. VersionAccept )
