Documentation
¶
Overview ¶
Package modelbinding resolves typed route keys into concrete models before domain handlers run. Transport DTOs and response contracts remain explicit.
Index ¶
- func DescribeAuthenticatedEndpoint[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R]) (foundryhttp.EndpointInfo, error)
- func DescribeAuthenticatedIdempotentEndpoint[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) (foundryhttp.EndpointInfo, error)
- func DescribeEndpoint[P, Q, B, M, R any](e Endpoint[P, Q, B, M, R]) (foundryhttp.EndpointInfo, error)
- func DescribeIdempotentEndpoint[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R]) (foundryhttp.EndpointInfo, error)
- func Resolve[P, M any](r Resolver[P, M], ctx context.Context, path P) (M, error)
- func ValidateAuthenticatedEndpoint[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R]) error
- func ValidateAuthenticatedIdempotentEndpoint[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) error
- func ValidateEndpoint[P, Q, B, M, R any](e Endpoint[P, Q, B, M, R]) error
- func ValidateIdempotentEndpoint[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R]) error
- func ValidateResolver[P, M any](r Resolver[P, M]) error
- type AuthenticatedEndpoint
- func AuthorizeAuthenticatedResource[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R], ...) AuthenticatedEndpoint[P, Q, B, S, M, R]
- func BindAuthenticated[P, Q, B, S, M, R any](transport AuthenticatedTransport[P, Q, B, S, R], resolver Resolver[P, M]) AuthenticatedEndpoint[P, Q, B, S, M, R]
- type AuthenticatedIdempotentEndpoint
- func AuthenticatedIdempotentHeaders[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R], ...) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
- func AuthorizeAuthenticatedIdempotentResource[P, Q, B, S, M, R any](endpoint AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R], ...) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
- func BindAuthenticatedIdempotent[P, Q, B, S, M, R any](endpoint foundryhttp.AuthenticatedIdempotentEndpoint[P, Q, B, S, R], ...) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
- type AuthenticatedTransport
- type Endpoint
- type IdempotentEndpoint
- func AuthorizeIdempotentResource[P, Q, B, M, R any](endpoint IdempotentEndpoint[P, Q, B, M, R], ...) IdempotentEndpoint[P, Q, B, M, R]
- func BindIdempotent[P, Q, B, M, R any](endpoint foundryhttp.IdempotentEndpoint[P, Q, B, R], resolver Resolver[P, M]) IdempotentEndpoint[P, Q, B, M, R]
- func IdempotentHeaders[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R], ...) IdempotentEndpoint[P, Q, B, M, R]
- type Input
- type KeyQuery
- type Models
- type Resolver
- func ByColumn[P, M any, K comparable](executor database.Executor, source orm.Query[M], field orm.KeyColumn[M, K], ...) Resolver[P, M]
- func ByKey[P, M, K any](executor database.Executor, source KeyQuery[M, K], key func(P) K) Resolver[P, M]
- func Define[P, M any](lookup func(context.Context, P) (value.Optional[M], error)) Resolver[P, M]
- func Then[P, A, B any](parent Resolver[P, A], ...) Resolver[P, Models[A, B]]
- func ThroughRelation[P, A, B any, K comparable, R orm.DirectRelation[A, B]](executor database.Executor, parent Resolver[P, A], relation R, ...) Resolver[P, Models[A, B]]
- func ThroughSelectedRelation[P, A, M, B any, K comparable, R orm.DirectRelation[M, B]](executor database.Executor, parent Resolver[P, A], selectParent func(A) M, ...) Resolver[P, Models[A, B]]
- func WithMissing[P, M any](r Resolver[P, M], missing func(context.Context, P) error) Resolver[P, M]
- type Transport
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DescribeAuthenticatedEndpoint ¶ added in v0.2.0
func DescribeAuthenticatedEndpoint[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R]) (foundryhttp.EndpointInfo, error)
DescribeAuthenticatedEndpoint validates the model-binding declaration and returns transport metadata.
func DescribeAuthenticatedIdempotentEndpoint ¶ added in v0.2.0
func DescribeAuthenticatedIdempotentEndpoint[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) (foundryhttp.EndpointInfo, error)
DescribeAuthenticatedIdempotentEndpoint validates the model-binding declaration and returns authentication and idempotency metadata.
func DescribeEndpoint ¶ added in v0.2.0
func DescribeEndpoint[P, Q, B, M, R any](e Endpoint[P, Q, B, M, R]) (foundryhttp.EndpointInfo, error)
DescribeEndpoint retains transport metadata without treating the stored model as a public request or response DTO. Model lookup does not change wire types.
func DescribeIdempotentEndpoint ¶ added in v0.2.0
func DescribeIdempotentEndpoint[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R]) (foundryhttp.EndpointInfo, error)
DescribeIdempotentEndpoint validates the model-binding declaration and returns idempotency metadata.
func Resolve ¶ added in v0.2.0
Resolve validates the declaration, then performs exactly one lookup, returning 404 (or the WithMissing error) for an omitted result. A failed or canceled lookup publishes no partial model. Panic and Goexit remain internal failures; cancellation never abandons a running callback. Resolving a route model does not authorize access or lock the row.
func ValidateAuthenticatedEndpoint ¶ added in v0.2.0
func ValidateAuthenticatedEndpoint[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R]) error
ValidateAuthenticatedEndpoint checks the authenticated transport, resolver and any resource-authorization callback.
func ValidateAuthenticatedIdempotentEndpoint ¶ added in v0.2.0
func ValidateAuthenticatedIdempotentEndpoint[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) error
ValidateAuthenticatedIdempotentEndpoint checks resource authorization, authenticated idempotency and model resolver declarations.
func ValidateEndpoint ¶ added in v0.2.0
ValidateEndpoint checks the transport, resolver and any resource-authorization callback.
func ValidateIdempotentEndpoint ¶ added in v0.2.0
func ValidateIdempotentEndpoint[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R]) error
ValidateIdempotentEndpoint checks resource authorization, idempotency and model resolver declarations.
func ValidateResolver ¶ added in v0.2.0
ValidateResolver checks the declaration without resolving a model or opening a transaction. Custom declaration callbacks remain owned until they return. Endpoints validate once at registration; nested resolvers validate each ancestor once through their composed check.
Types ¶
type AuthenticatedEndpoint ¶
type AuthenticatedEndpoint[P, Q, B, S, M, R any] struct { // contains filtered or unexported fields }
AuthenticatedEndpoint retains two independent model types: the transport's subject S and the bound resource M. For an optional transport S is Optional[A]. A resource lookup is not authorization; apply a concrete resource policy too.
func AuthorizeAuthenticatedResource ¶ added in v0.2.0
func AuthorizeAuthenticatedResource[P, Q, B, S, M, R any](e AuthenticatedEndpoint[P, Q, B, S, M, R], authorize func(context.Context, S, Input[P, Q, B, M]) error) AuthenticatedEndpoint[P, Q, B, S, M, R]
AuthorizeAuthenticatedResource preserves both the concrete guard actor (including optional actors) and the complete bound resource. Relationship matching is not a grant.
func BindAuthenticated ¶
func BindAuthenticated[P, Q, B, S, M, R any](transport AuthenticatedTransport[P, Q, B, S, R], resolver Resolver[P, M]) AuthenticatedEndpoint[P, Q, B, S, M, R]
BindAuthenticated connects a typed model resolver to an authenticated binding transport.
func (AuthenticatedEndpoint[P, Q, B, S, M, R]) Handle ¶
func (e AuthenticatedEndpoint[P, Q, B, S, M, R]) Handle(handler func(context.Context, S, Input[P, Q, B, M]) (R, error)) foundryhttp.RouteRegistration
Handle resolves and authorizes the bound model before invoking the typed subject handler at the transport's binding stage.
type AuthenticatedIdempotentEndpoint ¶
type AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R any] struct { // contains filtered or unexported fields }
AuthenticatedIdempotentEndpoint combines a typed model resolver and resource authorization with actor-aware idempotency.
func AuthenticatedIdempotentHeaders ¶ added in v0.2.0
func AuthenticatedIdempotentHeaders[P, Q, B, S, M, R any](e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R], fn func(context.Context, R) ([]foundryhttp.ResponseHeader, error)) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
AuthenticatedIdempotentHeaders returns an endpoint with application headers captured for exact replay.
func AuthorizeAuthenticatedIdempotentResource ¶ added in v0.2.0
func AuthorizeAuthenticatedIdempotentResource[P, Q, B, S, M, R any](endpoint AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R], authorize func(context.Context, S, Input[P, Q, B, M]) error) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
AuthorizeAuthenticatedIdempotentResource returns an endpoint with actor-aware resource authorization before idempotent execution or replay.
func BindAuthenticatedIdempotent ¶ added in v0.2.0
func BindAuthenticatedIdempotent[P, Q, B, S, M, R any](endpoint foundryhttp.AuthenticatedIdempotentEndpoint[P, Q, B, S, R], resolver Resolver[P, M]) AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]
BindAuthenticatedIdempotent attaches a typed model resolver to an authenticated idempotent endpoint.
func (AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) Handle ¶
func (e AuthenticatedIdempotentEndpoint[P, Q, B, S, M, R]) Handle(scope func(context.Context, S, Input[P, Q, B, M]) (idempotency.Scope, error), handler func(context.Context, *database.Tx, S, Input[P, Q, B, M]) (R, error)) foundryhttp.RouteRegistration
Handle resolves and authorizes the model before choosing the actor-aware scope and transaction handler for execution or replay.
type AuthenticatedTransport ¶ added in v0.2.0
type AuthenticatedTransport[P, Q, B, S, R any] interface { // Validate checks the authenticated transport declaration. Validate() error // Description returns the authenticated endpoint's contract metadata. Description() (foundryhttp.EndpointInfo, error) // HandleBound registers a binding stage receiving the concrete subject and typed // request. HandleBound(foundryhttp.AuthenticatedBinding[P, Q, B, S, R]) foundryhttp.RouteRegistration }
AuthenticatedTransport requires explicit binding-stage ownership.
type Endpoint ¶
type Endpoint[P, Q, B, M, R any] struct { // contains filtered or unexported fields }
Endpoint binds one concrete model to a transport declaration. Configure the original endpoint before Bind; use it for typed URL generation as usual.
func AuthorizeResource ¶ added in v0.2.0
func AuthorizeResource[P, Q, B, M, R any](e Endpoint[P, Q, B, M, R], authorize func(context.Context, Input[P, Q, B, M]) error) Endpoint[P, Q, B, M, R]
AuthorizeResource configures a resource policy after the complete model bundle resolves. On framework endpoints it runs at the binding stage, before validation and domain work. Request-only authorization belongs on the original HTTP endpoint and runs before any model lookups.
func Bind ¶
func Bind[P, Q, B, M, R any](transport Transport[P, Q, B, R], resolver Resolver[P, M]) Endpoint[P, Q, B, M, R]
Bind composes model resolution with a transport. Framework endpoints resolve the model (and apply AuthorizeResource) at their binding stage: after request authorization, before validation. A missing model is therefore 404 and a resource denial 403 before body validation reports 422, and the resolved model reaches the handler without a second lookup. Custom transports implement this stage explicitly, or opt into http.AfterValidation to resolve before their handler. No database I/O occurs during construction/registration.
func (Endpoint[P, Q, B, M, R]) Handle ¶
func (e Endpoint[P, Q, B, M, R]) Handle(handler func(context.Context, Input[P, Q, B, M]) (R, error)) foundryhttp.RouteRegistration
Handle requires the declared model, path/query/body and response types. The resolver runs once per accepted request. It does not start a transaction or cache a model across requests; the handler owns business transactions.
type IdempotentEndpoint ¶
type IdempotentEndpoint[P, Q, B, M, R any] struct { // contains filtered or unexported fields }
IdempotentEndpoint resolves and authorizes the resource on every request, then supplies the same concrete model and request to a transaction-bound callback.
func AuthorizeIdempotentResource ¶ added in v0.2.0
func AuthorizeIdempotentResource[P, Q, B, M, R any](endpoint IdempotentEndpoint[P, Q, B, M, R], authorize func(context.Context, Input[P, Q, B, M]) error) IdempotentEndpoint[P, Q, B, M, R]
AuthorizeIdempotentResource returns an endpoint with resource authorization before idempotent execution or replay.
func BindIdempotent ¶ added in v0.2.0
func BindIdempotent[P, Q, B, M, R any](endpoint foundryhttp.IdempotentEndpoint[P, Q, B, R], resolver Resolver[P, M]) IdempotentEndpoint[P, Q, B, M, R]
BindIdempotent attaches a typed model resolver to an idempotent endpoint.
func IdempotentHeaders ¶ added in v0.2.0
func IdempotentHeaders[P, Q, B, M, R any](e IdempotentEndpoint[P, Q, B, M, R], fn func(context.Context, R) ([]foundryhttp.ResponseHeader, error)) IdempotentEndpoint[P, Q, B, M, R]
IdempotentHeaders returns an endpoint with application headers captured for exact replay.
func (IdempotentEndpoint[P, Q, B, M, R]) Handle ¶
func (e IdempotentEndpoint[P, Q, B, M, R]) Handle(scope func(context.Context, Input[P, Q, B, M]) (idempotency.Scope, error), handler func(context.Context, *database.Tx, Input[P, Q, B, M]) (R, error)) foundryhttp.RouteRegistration
Handle resolves and authorizes the model before choosing the scope and transaction handler for execution or replay.
type Input ¶
type Input[P, Q, B, M any] struct { Request foundryhttp.Input[P, Q, B] Model M }
Input preserves the original typed transport request alongside its loaded model. The model is available to domain code, never added to the wire schema.
type KeyQuery ¶
type KeyQuery[M, K any] interface { // Validate checks the typed key-query declaration. Validate() error // Find looks up a model by its concrete key using the supplied executor, returning // omission when absent. Find(context.Context, database.Executor, K) (value.Optional[M], error) }
KeyQuery is satisfied by orm.Keyed and legacy generated model queries. Both model M and key K remain concrete; a query for one model cannot resolve another model's ID. Find retains the query's filters, eager loads, soft-delete scope and retrieval hooks. Transaction-only locked queries have a different executor contract.
type Models ¶
type Models[P, C any] struct { Parent P Child C }
Models carries every concrete result in a nested lookup. Parent may itself be Models for another level. Nothing is placed in a heterogeneous context map.
type Resolver ¶
type Resolver[P, M any] struct { // contains filtered or unexported fields }
Resolver owns one lookup from decoded path P to model M. It retains no request result between calls. Define supports custom route keys and scopes; ByKey reuses a generated model query's typed primary-key lookup.
func ByColumn ¶
func ByColumn[P, M any, K comparable](executor database.Executor, source orm.Query[M], field orm.KeyColumn[M, K], key func(P) K) Resolver[P, M]
ByColumn resolves an ORM alternate key within the supplied query's scope. Duplicate matches fail; no transaction or lock is acquired. Example: modelbinding.ByColumn(db,Users.Query(),orm.TextExpr(Users.Email),emailFromPath).
func ByKey ¶
func ByKey[P, M, K any](executor database.Executor, source KeyQuery[M, K], key func(P) K) Resolver[P, M]
ByKey binds a decoded path key to a scoped primary-key lookup. Example: modelbinding.ByKey(db,orm.Keyed(Users.Query(),Users.Key()),pathKey). The executor is supplied by application assembly, not retrieved from a global container. For a stored alternate key use ByField; Through composes declared parent/child relationships. Define remains available for custom application scopes.
func Define ¶
Define declares a custom, context-aware lookup. Return an omitted Optional for an absent model. Returned errors remain ordinary domain/infrastructure errors; they are never treated as an absent record. The callback must be safe for concurrent requests and return only fully hydrated models.
func Then ¶
func Then[P, A, B any](parent Resolver[P, A], child func(context.Context, P, A) (value.Optional[B], error)) Resolver[P, Models[A, B]]
Then resolves the parent once, then supplies that model and the original path to a custom child lookup. No partial bundle escapes. Callbacks borrow input, must be concurrency-safe and retain ownership until they return after cancel.
func ThroughRelation ¶
func ThroughRelation[P, A, B any, K comparable, R orm.DirectRelation[A, B]](executor database.Executor, parent Resolver[P, A], relation R, field orm.KeyColumn[B, K], key func(P) K) Resolver[P, Models[A, B]]
ThroughRelation resolves a child through a direct ORM relationship. Example: modelbinding.ThroughRelation(db,teams,TeamRelations.Projects,orm.TextExpr(Projects.Slug),slugFromPath).
func ThroughSelectedRelation ¶
func ThroughSelectedRelation[P, A, M, B any, K comparable, R orm.DirectRelation[M, B]](executor database.Executor, parent Resolver[P, A], selectParent func(A) M, relation R, field orm.KeyColumn[B, K], key func(P) K) Resolver[P, Models[A, B]]
ThroughSelectedRelation extends a nested ORM binding while retaining earlier models. Example: modelbinding.ThroughSelectedRelation(db,projects,func(p Models[Team,Project])Project{return p.Child},ProjectRelations.Tasks,orm.TextExpr(Tasks.Slug),slugFromPath).
func WithMissing ¶ added in v0.2.0
WithMissing replaces the default 404 for an omitted lookup result. The callback receives the decoded path and returns the error to report, such as a declared application error; returning nil still reports NotFound. It runs in an owned callback and is never invoked for lookup failures.
type Transport ¶
type Transport[P, Q, B, R any] interface { // Validate checks the binding transport declaration. Validate() error // Description returns the endpoint's contract metadata. Description() (foundryhttp.EndpointInfo, error) // HandleBound registers the typed request's model-binding stage. HandleBound(foundryhttp.Binding[P, Q, B, R]) foundryhttp.RouteRegistration }
Transport is the endpoint capability used by the binding adapter. Ordinary ForBinding and ForSignedBinding construct it, preserving signature checks and all existing middleware, decoding, validation, errors and response contracts.