Documentation
¶
Overview ¶
Package celerity is the entry point to the Celerity Go SDK: it holds the application, the registration API, and the handler registry those produce.
Registration is explicit rather than derived from decorators or struct tags, which is what the Node and Python SDKs use and what Go has no equivalent of. Dependencies reach a handler through the closure or the receiver, the way they do in any Go program:
app := celerity.New()
celerity.Get(app, "/orders/{orderId}", orders.Get(store))
celerity.Run(app)
Index ¶
- Constants
- Variables
- func AddGuard(app *App, name string, g Guard)
- func ConnectionID(ctx context.Context) string
- func Consume(app *App, sourceID string, ...)
- func CustomTag(handlerName string) string
- func Delete[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func EventFrom(ctx context.Context) (*handler.Event, bool)
- func Get[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func HTTP(app *App, method, route string, ...)
- func HTTPTag(method, route string) string
- func Handler[In, Out any](app *App, name string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func Invoke[In, Out any](app *App, name string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func NormaliseRoute(route string) string
- func OnConnect[In, Out any](app *App, h HandlerFunc[In, Out], opts ...RegisterOption)
- func OnDisconnect[In, Out any](app *App, h HandlerFunc[In, Out], opts ...RegisterOption)
- func OnMessage[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func Patch[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func Post[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func Put[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
- func RequestID(ctx context.Context) string
- func Run(app *App)
- func RunContext(ctx context.Context, app *App) error
- func Schedule(app *App, sourceID string, ...)
- func SourceTag(sourceID, handlerName string) string
- func WebSocketEventFrom(ctx context.Context) (*handler.WebSocketMessage, bool)
- func WebSocketSenderFrom(ctx context.Context) (handler.WebSocketSender, bool)
- func WebSocketTag(routeKey, route string) string
- func WithEvent(ctx context.Context, ev *handler.Event) context.Context
- type App
- func (a *App) Adapter() serverless.Adapter
- func (a *App) Config() *config.Service
- func (a *App) Err() error
- func (a *App) Extracting() bool
- func (a *App) HandlerLimits() map[string]int
- func (a *App) Logger() telemetry.Logger
- func (a *App) Manifest() *manifest.Manifest
- func (a *App) Pipeline(reg *Registration) layer.Next
- func (a *App) ReconcileTags(blueprint []BlueprintHandler) ([]string, error)
- func (a *App) RecordResourceRef(kind resources.Kind, name string)
- func (a *App) Registry() *Registry
- func (a *App) Resolver() serverless.Resolver
- func (a *App) ResourceError(err error)
- func (a *App) ResourceProvider() resources.Provider
- func (a *App) ResourceRefs() map[resources.Kind][]string
- type BlueprintHandler
- type Guard
- type HandlerFunc
- type Mode
- type Option
- func WithAdapter(a serverless.Adapter) Option
- func WithConfig(svc *config.Service) Option
- func WithLayers(layers ...layer.Layer) Option
- func WithLogger(l telemetry.Logger) Option
- func WithResourceProvider(p resources.Provider) Option
- func WithValidator(v Validator) Option
- func WithWebSocketRouteKey(key string) Option
- type RegisterOption
- func MaxConcurrent(n int) RegisterOption
- func Named(name string) RegisterOption
- func ProtectedBy(guards ...string) RegisterOption
- func Public() RegisterOption
- func PublishedAs(name string) RegisterOption
- func SkipValidation() RegisterOption
- func Uses(resourceNames ...string) RegisterOption
- func ValidateWith(v Validator) RegisterOption
- func With(layers ...layer.Layer) RegisterOption
- type Registration
- type Registry
- func (r *Registry) Add(reg *Registration) error
- func (r *Registry) All() []*Registration
- func (r *Registry) ByName(name string) (*Registration, bool)
- func (r *Registry) Get(tag string) (*Registration, bool)
- func (r *Registry) Len() int
- func (r *Registry) OfKind(kind handler.Kind) []*Registration
- func (r *Registry) Retag(from, to string)
- func (r *Registry) Tags() []string
- type SelfValidating
- type StatusCoder
- type StatusError
- type UnresolvedHandlerError
- type ValidationError
- type ValidationIssue
- type Validator
Constants ¶
const ( RouteConnect = "$connect" RouteDisconnect = "$disconnect" RouteDefault = "$default" )
WebSocket routes with a meaning of their own. A message carrying no route, or one nothing else serves, is dispatched to RouteDefault.
const DefaultWebSocketRouteKey = "event"
DefaultWebSocketRouteKey is the field a WebSocket message carries its route in when the API does not state one.
It matches the runtime's DEFAULT_WEBSOCKET_API_ROUTE_KEY, which is what a blueprint omitting spec.websocketConfig.routeKey resolves to, so a handler registered against a default API declares the tag the runtime builds.
const Version = "0.1.0"
Version is the SDK version declared to the runtime in the handshake.
Variables ¶
var ( Status = handler.Status Statusf = handler.Statusf WrapWithStatus = handler.Wrap BadRequest = handler.BadRequest Forbidden = handler.Forbidden NotFound = handler.NotFound Conflict = handler.Conflict Gone = handler.Gone UnprocessableEntity = handler.UnprocessableEntity TooManyRequests = handler.TooManyRequests NotImplemented = handler.NotImplemented )
var ( Invalid = handler.Invalid Issue = handler.Issue )
Re-exported so an application builds issues without a second import.
Functions ¶
func AddGuard ¶
AddGuard registers a named guard that handlers refer to through ProtectedBy.
func ConnectionID ¶
ConnectionID returns the WebSocket connection the event arrived on, or the empty string for any other source.
func Consume ¶
func Consume( app *App, sourceID string, h func(context.Context, *handler.ConsumerBatch) (*handler.BatchResult, error), opts ...RegisterOption, )
Consume registers a handler for batches from a queue, stream or event source.
The handler is given the whole batch and returns a handler.BatchResult, so that one failing record redrives that record rather than the batch.
func Delete ¶
func Delete[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
Delete registers a handler for DELETE requests to route.
func Get ¶
func Get[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
Get registers a handler for GET requests to route.
func HTTP ¶
func HTTP( app *App, method, route string, h func(context.Context, *handler.Request) (*handler.Response, error), opts ...RegisterOption, )
HTTP registers a handler that works in the wire vocabulary directly, for the cases where decoding into a typed request is not what is wanted.
func HTTPTag ¶
HTTPTag returns the tag identifying an HTTP handler.
Route must already be in the router's form, which NormaliseRoute produces.
func Handler ¶
func Handler[In, Out any]( app *App, name string, h HandlerFunc[In, Out], opts ...RegisterOption, )
Handler registers a handler that takes its wiring from the blueprint.
Code states the name and nothing else and the route, method or source is the decided in the blueprint, and the tag is settled against what the blueprint declares before this process declares itself. The blueprint's annotations carry the routing information in this case.
celerity.Handler(app, "getOrderHandler", getOrder)
Everything the blueprint has no concept of is still stated here, so taking wiring from the blueprint costs nothing else:
celerity.Handler(app, "forwardPayload", forward,
celerity.SkipValidation(),
celerity.With(ratelimit.Layer(100)),
celerity.ProtectedBy("jwt"),
celerity.MaxConcurrent(2),
)
A name the blueprint does not declare fails the handshake naming it, rather than leaving a handler that can never be reached.
Consumer and schedule handlers take a batch and a trigger rather than a decoded input, so they are registered with Consume and Schedule even when their source comes from the blueprint.
func Invoke ¶
func Invoke[In, Out any]( app *App, name string, h HandlerFunc[In, Out], opts ...RegisterOption, )
Invoke registers a handler reachable by name, from another handler or from the runtime's local invoke endpoint.
func NormaliseRoute ¶
NormaliseRoute converts a blueprint route template into the router's form, which is what handler tags and handler.Request.Route are built from.
/files/{path+} -> /files/{*path}
It is handler.NormaliseRoute: the same translation a serverless adapter applies when it maps a route the platform states in the blueprint's form, so there is one definition of the router's spelling rather than one per mapper.
func OnConnect ¶
func OnConnect[In, Out any](app *App, h HandlerFunc[In, Out], opts ...RegisterOption)
OnConnect registers a handler run when a WebSocket client connects.
func OnDisconnect ¶
func OnDisconnect[In, Out any](app *App, h HandlerFunc[In, Out], opts ...RegisterOption)
OnDisconnect registers a handler run when a WebSocket client disconnects.
func OnMessage ¶
func OnMessage[In, Out any]( app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption, )
OnMessage registers a handler for WebSocket messages arriving on a route.
The route is the value carried by the API's route key, so a message of {"action": "sendMessage", ...} reaches the handler registered for "sendMessage" when the API's route key is "action". Which field that is belongs to the API rather than to this handler: see WithWebSocketRouteKey.
Register RouteDefault to catch messages no other route matches.
func Patch ¶
func Patch[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
Patch registers a handler for PATCH requests to route.
func Post ¶
func Post[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
Post registers a handler for POST requests to route.
func Put ¶
func Put[In, Out any](app *App, route string, h HandlerFunc[In, Out], opts ...RegisterOption)
Put registers a handler for PUT requests to route.
func RequestID ¶
RequestID returns the identifier the runtime gave this delivery, whatever the source, which is what ties a handler's own logging to the runtime's.
func Run ¶
func Run(app *App)
Run starts the application, choosing how from the environment, and blocks until it is shut down.
The mode is taken from the environment rather than chosen by the developer so that one binary serves every deployment target: the same artefact runs under the runtime, under Lambda, and under the CLI's extraction step.
func RunContext ¶
RunContext is Run with a caller-supplied context, for tests and for applications that own their own shutdown signalling.
func Schedule ¶
func Schedule( app *App, sourceID string, h func(context.Context, *handler.ScheduleTrigger) error, opts ...RegisterOption, )
Schedule registers a handler run when a scheduled rule fires.
func SourceTag ¶
SourceTag returns the tag identifying a consumer or schedule handler, keyed by the source it is bound to.
func WebSocketEventFrom ¶
func WebSocketEventFrom(ctx context.Context) (*handler.WebSocketMessage, bool)
WebSocketEventFrom returns the WebSocket message being handled.
It is how a handler reaches the connection it should answer on where a WebSocket message is acknowledged rather than replied to, so anything the client sees is pushed back through WebSocketSenderFrom to a connection named here.
func WebSocketSenderFrom ¶
func WebSocketSenderFrom(ctx context.Context) (handler.WebSocketSender, bool)
WebSocketSenderFrom returns the sender a handler pushes to connected clients through.
It is the runtime's IPC side channel under the Celerity runtime and the provider's push API under a serverless adapter, and a handler does not need to know which. The second return value is false when the event's source has no sender, which is every source other than WebSocket.
func WebSocketTag ¶
WebSocketTag returns the tag identifying a WebSocket message handler.
The route key names the field carrying the route, and the route is its value, so {"action": "sendMessage"} on an API keyed by "action" is action::sendMessage. Both halves come from the API rather than the handler, which is why registration takes only the route.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is one Celerity application: everything it serves, and how it should serve it.
func (*App) Adapter ¶
func (a *App) Adapter() serverless.Adapter
Adapter returns an adapter given explicitly, or nil when the linked one is to be used.
func (*App) Config ¶
Config returns the application's configuration.
This is never nil, an application whose deployment described no store gets a service with no namespaces, so a provider reading it is told the application declares no celerity/config resource rather than having to guard against nothing.
Read by resource providers resolving a blueprint name to the identifier a deployment recorded. A handler is given the service as an argument instead.
func (*App) Extracting ¶
Extracting reports that this process is describing itself for the CLI rather than serving, satisfying resources.Host.
func (*App) HandlerLimits ¶
HandlerLimits returns the per-handler concurrency caps, keyed by tag.
Read after App.ReconcileTags rather than before as reconciliation can change a WebSocket handler's tag to the one the blueprint declares, and a cap keyed by the tag built before that would name a handler the runtime does not know.
func (*App) Manifest ¶
Manifest builds the handler manifest for this application.
Resource references are left to the extraction tool's static pass: a reference captured in a closure is not reachable from a running program, so filling the annotation in here would report only what happened to be visible and would look complete while being wrong.
func (*App) Pipeline ¶
func (a *App) Pipeline(reg *Registration) layer.Next
Pipeline builds the full entry point for a registration: guards, then layers outermost to innermost, then the handler.
It is exported so that a serverless adapter maintained outside this repository composes the same pipeline the in-repo ones do, rather than approximating it.
func (*App) ReconcileTags ¶
func (a *App) ReconcileTags(blueprint []BlueprintHandler) ([]string, error)
ReconcileTags settles every tag that code could not state on its own, and returns the tags this process serves.
Two kinds of handler need it, for opposite reasons.
A handler registered with Handler states only its name where its route, method or source is the blueprint's to decide, so its tag is whatever the blueprint gives the handler of that name. One that the blueprint does not declare is an error rather than a handler with no tag, since it could never be dispatched to.
A WebSocket handler registered with OnMessage states its route, matching the other language SDKs where a decorator carries it and extraction writes it into the blueprint. The route key belongs to the API, so it is taken from whatever the blueprint keys that route by. One left unmatched keeps the tag built from WithWebSocketRouteKey, so the handshake reports the tag the handler actually declared rather than hiding a mismatch behind a guess.
The runtime sends what the blueprint declares before this process declares itself, which is the only window in which both are known.
func (*App) RecordResourceRef ¶
RecordResourceRef notes that the application reaches a resource, satisfying resources.Host.
This is the application-wide set. Per-handler attribution comes from the static extraction pass, which is the only thing that can see through a closure; this set is what that pass is cross-checked against, so a reference the run saw and the analysis missed is reported rather than silently dropped.
func (*App) Registry ¶
Registry returns the handlers registered so far.
Serverless adapters and the manifest emitter read the application through it.
func (*App) Resolver ¶
func (a *App) Resolver() serverless.Resolver
Resolver adapts the registry to what a serverless adapter resolves through.
Run uses it, and an application that owns its own entry point rather than handing control to Run passes it to serverless.Serve or serverless.NewInvoker itself.
func (*App) ResourceError ¶
ResourceError collects a resource that could not be built, satisfying resources.Host.
func (*App) ResourceProvider ¶
ResourceProvider returns a provider given explicitly, satisfying resources.Host. Nil means the linked provider is used.
type BlueprintHandler ¶
type BlueprintHandler struct {
// Name is the blueprint resource name.
Name string
// PublishedName is the name the blueprint publishes the handler under, from
// spec.handlerName. Empty where it sets none.
PublishedName string
// Tag is what the runtime addresses the handler by.
Tag string
}
BlueprintHandler is one handler the blueprint declares, as the runtime reports it before the handshake.
It is this package's own type rather than the protocol's, so reconciliation can be described and tested without the wire contract.
type HandlerFunc ¶
HandlerFunc is a typed handler: the framework decodes the request into In and encodes Out into the response, so a handler deals only in its own types.
type Mode ¶
type Mode string
Mode is how an application was asked to run.
func DetectMode ¶
func DetectMode() Mode
DetectMode reports how the process was asked to run.
The runtime's own variables are checked first: a handler process started by the runtime is told so explicitly, whereas a serverless platform is inferred.
type Option ¶
type Option func(*options)
Option configures an application.
func WithAdapter ¶
func WithAdapter(a serverless.Adapter) Option
WithAdapter supplies the serverless adapter explicitly.
Applications do not normally need it: importing an adapter registers it, and the one whose platform the process is running on is selected at startup. It is here for a test that wants to drive a fake adapter.
func WithConfig ¶
WithConfig supplies the configuration service explicitly.
Applications do not normally need it as the stores a blueprint's celerity/config resources were deployed as are described in the environment, and reading them needs whichever provider module is linked, so config.FromEnvironment does this at startup. It is here for a test and for a local run that wants to read from a map rather than reach a real store:
cfg := config.New()
cfg.Register("settings", config.NewNamespace(
config.MapBackend{"settings": {"REGION": "eu-west-2"}}, "settings"))
app := celerity.New(celerity.WithConfig(cfg))
The service is not put in a handler's context. It exists before any event does and is the same object for every one of them, so a handler that reads configuration is given it, the way it is given a store or a client:
celerity.Get(app, "/orders", orders.List(store, cfg))
func WithLayers ¶
WithLayers adds application-scoped layers, which wrap every handler.
func WithLogger ¶
WithLogger replaces the logger handlers receive through telemetry.LoggerFrom.
Without one an application writes through telemetry.NewLogger: JSON where a log aggregator is reading, human-readable in a development session.
func WithResourceProvider ¶
WithResourceProvider supplies the platform implementation behind the resource interfaces explicitly.
Applications do not normally need it: importing a provider registers it, and the linked one is used. It is here for a test that wants to supply a fake.
func WithValidator ¶
WithValidator sets the validator run over every decoded input, after the input's own Validate where it has one.
func WithWebSocketRouteKey ¶
WithWebSocketRouteKey sets the field in a WebSocket message that carries the route, which is a property of the API rather than of any handler:
{"action": "sendMessage", "data": {...}}
Under the Celerity runtime this is a fallback. The blueprint states it, and the runtime sends every declared handler tag before the handshake, so the tags are reconciled against what the blueprint actually says. It matters where there is no runtime to ask, which is every serverless deployment.
type RegisterOption ¶
type RegisterOption func(*registerOptions)
RegisterOption configures one registration.
func MaxConcurrent ¶
func MaxConcurrent(n int) RegisterOption
MaxConcurrent caps how many events of this handler may be in flight at once, so a slow or expensive handler cannot consume the whole concurrency window and starve the others.
Unlike the size of that window, which depends on the host and is set by whoever deploys, this says which handler is expensive relative to the rest, and that is known here rather than at deployment. It is a cap, not a reservation, it never guarantees the handler that much.
func Named ¶
func Named(name string) RegisterOption
Named sets the blueprint resource name for a handler.
Without it the name is derived from the handler function's own name, which is what a blueprint generated from the manifest will use.
func ProtectedBy ¶
func ProtectedBy(guards ...string) RegisterOption
ProtectedBy names the guards that must allow an event before it reaches this handler.
func Public ¶
func Public() RegisterOption
Public marks a handler as reachable without authorisation, overriding an application-wide guard.
func PublishedAs ¶
func PublishedAs(name string) RegisterOption
PublishedAs sets the name a deployment addresses this handler by, which is the blueprint's spec.handlerName.
func SkipValidation ¶
func SkipValidation() RegisterOption
SkipValidation turns validation off for one handler, including the input's own Validate where it has one.
For a handler that takes what it is given, such as one accepting a payload it forwards without reading, or one whose checks depend on state the type cannot see.
func Uses ¶
func Uses(resourceNames ...string) RegisterOption
Uses declares blueprint resources this handler reaches, so the deployment grants it access to them.
Extraction finds resources through the reference graph on its own, and Uses is additive to that. It is for what analysis cannot see: a resource named by a value that is not a compile-time constant, or one reached by a mechanism the reference graph does not model.
There is no option to narrow. Removing a reference the walk found would let a handler call something it has no permission for, failing at runtime rather than at build time.
func ValidateWith ¶
func ValidateWith(v Validator) RegisterOption
ValidateWith uses a different validator for one handler, in place of the application's.
For a handler whose rules are not the rest of the application's, for example, a public endpoint that is stricter about what it accepts, or one migrating to new rules while the others keep the old.
func With ¶
func With(layers ...layer.Layer) RegisterOption
With adds handler-scoped layers, applied inside any application layers.
type Registration ¶
type Registration struct {
// Tag addresses this handler in the runtime, built by [HTTPTag] and friends.
Tag string
// Name is the blueprint resource name this handler is declared as.
Name string
// PublishedName is the name the blueprint publishes the handler under, from
// spec.handlerName. Empty when the blueprint does not set one.
PublishedName string
Kind handler.Kind
// Method and Route are set for HTTP handlers, Route in the router's form.
Method string
Route string
// RouteKey is set for WebSocket handlers.
RouteKey string
// SourceID is set for consumer and schedule handlers.
SourceID string
// SourceFile and SourceLine are the location of the registration call,
// captured for error messages and for the handler manifest.
SourceFile string
SourceLine int
// FuncPath is the fully qualified name of the handler function, which roots
// the extraction tool's static resource walk.
FuncPath string
Handler handler.Func
Layers []layer.Layer
Guards []string
// Uses names resources declared explicitly through [Uses], additive to what
// static extraction finds.
Uses []string
// Public marks a handler reachable without authorisation.
Public bool
// MaxConcurrent caps how many events of this handler may be in flight,
// zero meaning uncapped.
MaxConcurrent int
// FromBlueprint marks a handler that stated only its name, leaving its
// route, method or source to the blueprint. Its tag is settled by
// [App.ReconcileTags] rather than at registration.
FromBlueprint bool
}
Registration is one handler as it was registered, along with everything the framework needs in order to run it and everything the CLI needs in order to describe it.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds every handler an application has registered, keyed by tag.
It is the single source of truth for three things that must agree: what the dispatcher routes against, what the handshake declares to the runtime, and what the handler manifest reports to the CLI.
func (*Registry) Add ¶
func (r *Registry) Add(reg *Registration) error
Add registers a handler.
Registering two handlers under one tag is a programming error rather than a last-write-wins: the runtime addresses handlers by tag, so the second would silently take every event meant for the first.
func (*Registry) All ¶
func (r *Registry) All() []*Registration
All returns every registration in registration order.
func (*Registry) ByName ¶
func (r *Registry) ByName(name string) (*Registration, bool)
ByName returns the handler whose blueprint resource name or published name is name. Serverless adapters resolve CELERITY_HANDLER_ID through this.
func (*Registry) Get ¶
func (r *Registry) Get(tag string) (*Registration, bool)
Get returns the handler registered under tag.
func (*Registry) OfKind ¶
func (r *Registry) OfKind(kind handler.Kind) []*Registration
OfKind returns every registration for one event source.
type SelfValidating ¶
type SelfValidating interface {
Validate() error
}
SelfValidating is implemented by a request type that checks itself.
Returning a handler.ValidationError answers with structured detail; returning anything else is answered as a 400 with no detail, since a message this SDK did not compose may describe the implementation.
func (r CreateOrder) Validate() error {
if r.Total <= 0 {
return celerity.Invalid("the order is not valid",
celerity.Issue("too_small", "must be greater than zero", "total"))
}
return nil
}
type StatusCoder ¶
type StatusCoder = handler.StatusCoder
Errors carrying a status, re-exported so an application deals with one package. A handler returning one of these is answered with that status; any other error is a fault, reported to the runtime and answered 500.
func getOrder(ctx context.Context, in GetOrder) (Order, error) {
order, err := store.Get(ctx, in.OrderID)
if errors.Is(err, sql.ErrNoRows) {
return Order{}, celerity.NotFound("no such order")
}
return order, err
}
type StatusError ¶
type StatusError = handler.StatusError
Errors carrying a status, re-exported so an application deals with one package. A handler returning one of these is answered with that status; any other error is a fault, reported to the runtime and answered 500.
func getOrder(ctx context.Context, in GetOrder) (Order, error) {
order, err := store.Get(ctx, in.OrderID)
if errors.Is(err, sql.ErrNoRows) {
return Order{}, celerity.NotFound("no such order")
}
return order, err
}
type UnresolvedHandlerError ¶
type UnresolvedHandlerError struct {
// Names are registered in code and absent from the blueprint.
Names []string
// Declared are the names the blueprint does declare, which is what a typo
// is most easily spotted against.
Declared []string
}
UnresolvedHandlerError reports handlers that take their wiring from the blueprint and were not found in it.
func (*UnresolvedHandlerError) Error ¶
func (e *UnresolvedHandlerError) Error() string
type ValidationError ¶
type ValidationError = handler.ValidationError
type ValidationIssue ¶
type ValidationIssue = handler.ValidationIssue
type Validator ¶
Validator checks a decoded input.
It is what a struct-tag validation library is adapted through. The adapter should return a handler.ValidationError, or any error implementing handler.IssueReporter, so the caller is answered with issues rather than with a bare message.