Documentation
¶
Overview ¶
Package schema provides the `@schema NAME { Field Type `json:"..." default:"..." validate:"..."` ... }` directive. The declaration lands in meta["schemas"]. `:request-schema=NAME` and `:response-schema=NAME` attach explicit pipeline boundary contracts; prefixing the name with `!` rejects undeclared fields at that boundary. Requests receive defaults before validation; response schemas are validated without defaults and must not declare any `default` tags. Such declarations fail before execution. Extra fields remain allowed unless the corresponding boundary is strict.
Typical use:
@schema TestUser {
Name string `json:"name" default:"guest" validate:"required"`
}
@pipeline greet
:request-schema=TestUser
runtime.noop
@end
ApplyDefaults returns a new effective payload map, and schema validation passes that map to the pipeline's first action. NormalizeObject exposes encoding/json-compatible object normalization for Go values. Response boundaries validate this normalized view but return the original result, preserving typed values for callers and later composition.
Index ¶
- Constants
- Variables
- func ApplyDefaults(schema Schema, payload any) (map[string]any, error)
- func ApplyDefaultsAndValidate(ctx context.Context, schema Schema, payload any) (map[string]any, error)
- func Bundle(_ map[string]string) compiler.Bundle
- func Library() action.Library
- func NormalizeObject(value any) (map[string]any, error)
- func SplitFields(s Schema) (payload, config []string)
- func ToJSONSchema(s Schema) map[string]any
- func Validate(ctx context.Context, schema Schema, payload any) error
- func ValidateWithoutDefaults(ctx context.Context, schema Schema, payload any) error
- func WithContextSchemas(ctx context.Context, schemas []Schema) context.Context
- type Field
- type Kind
- type Schema
- type ValidateRequest
Constants ¶
const ( SchemaModifierName = "schema" RequestSchemaModifierName = "request-schema" ResponseSchemaModifierName = "response-schema" )
const ID = "schema"
Variables ¶
var Directive = compiler.Directive{ Name: "schema", Example: `@schema Plan { Summary string }`, Handler: handleDirective, OpaqueBlock: true, }
Directive parses `@schema NAME { ... }` into a Schema appended to meta["schemas"]. Duplicate names are a compile error.
var RequestSchemaModifier = compiler.String(RequestSchemaModifierName, func(b *action.Builder[any, any], name string) *action.Builder[any, any] { return b.Tag("request-schema:" + name) })
var ResponseSchemaModifier = compiler.String(ResponseSchemaModifierName, func(b *action.Builder[any, any], name string) *action.Builder[any, any] { return b.Tag("response-schema:" + name) })
var SchemaModifier = compiler.String(SchemaModifierName, func(b *action.Builder[any, any], name string) *action.Builder[any, any] { return b.Tag("schema:" + name) })
SchemaModifier attaches schema metadata to an atom. Pipeline boundaries use the explicit request-schema and response-schema header modifiers instead.
var ValidateAction = action.New("schema.validate", func(ctx context.Context, req ValidateRequest) (any, error) { if req.Name == "" { return nil, xerr.BadRequest("schema.validate: schema name is required (use @{ name: \"SchemaName\" })") } schemas, _ := schemasContextKey.From(ctx) targetSchema, ok := schemas[req.Name] if !ok { return nil, xerr.NotFound("schema.validate: schema '" + req.Name + "' not registered in workflow") } targetPayload := req.Payload if targetPayload == nil { targetPayload, _ = rootInputKey.From(ctx) } if targetPayload == nil { return nil, xerr.BadRequest("schema.validate: no payload available to validate") } effective, err := ApplyDefaultsAndValidate(ctx, targetSchema, targetPayload) if err != nil { return nil, err } return effective, nil }).Description("Validate payload against a declared @schema"). Tag("schema", "validation"). Build()
Functions ¶
func ApplyDefaults ¶ added in v0.30.2
ApplyDefaults returns a copy of payload with each missing field filled from its schema field's `default` tag. Explicitly supplied values, including nil, are preserved. The input map is never modified.
Scalar defaults are parsed according to the declared field type. Slice, map, and struct defaults use JSON values, for example `default:"[1,2]"` or `default:"{\"enabled\":true}"`.
func ApplyDefaultsAndValidate ¶ added in v0.30.3
func ApplyDefaultsAndValidate(ctx context.Context, schema Schema, payload any) (map[string]any, error)
ApplyDefaultsAndValidate returns the effective payload after applying missing defaults and validating the declared fields. Explicit input values, including typed slice values, are preserved.
func NormalizeObject ¶ added in v0.40.0
NormalizeObject returns the JSON-visible fields of value as a generic object. It follows encoding/json semantics for field visibility, json tags, embedded fields, pointers, custom marshalers, and omitempty. Nested objects become map[string]any, arrays become []any, and JSON numbers become float64.
A nil value, nil pointer, or value that encodes as a non-object is rejected. The input is not modified. Use the returned view for inspection or validation; retain the original value when typed output must be preserved.
func SplitFields ¶ added in v0.17.0
func ToJSONSchema ¶ added in v0.22.0
func Validate ¶
Validate applies missing defaults and checks payload against the declared schema.
For every field that is present, the check proceeds in two stages:
- Go-kind check (checkFieldKind): the payload value's kind must match the schema field's declared type.
- Tag check (validation.Var): when the field carries a `validate:"..."` tag beyond bare "required", the value is validated against the tag expression using the same validator/v10 instance that powers validation.Struct.
The presence check for validate:"required" is handled inline, so a missing field reports as "is required" without invoking the validator. An empty string for a required field is also reported as "is required" because validator/v10 treats empty as the zero value.
ctx is threaded from the caller so context-aware custom rules registered via validation.RegisterCustom see the live context, and so a canceled invocation aborts validation promptly.
func ValidateWithoutDefaults ¶ added in v0.40.0
ValidateWithoutDefaults checks a payload against a schema without adding default values or changing the payload. Unknown fields are left untouched.