-
-
Notifications
You must be signed in to change notification settings - Fork 0
Server Request Schemas
Effuse provides a framework-owned schema vocabulary for server params, query, headers, JSON, and form data. Application code does not import Effect or install a second schema package.
import {
defineLayer,
serverSchema,
type ServerSchemaInput,
type ServerSchemaOutput,
} from '@effuse/core/server';
const SearchQuery = serverSchema.object({
filter: serverSchema.string,
page: serverSchema.optional(serverSchema.numberFromString, 1),
});
type SearchQueryInput = ServerSchemaInput<typeof SearchQuery>;
// { filter: string; page?: string }
type SearchQueryOutput = ServerSchemaOutput<typeof SearchQuery>;
// { filter: string; page: number }Input represents values accepted at the boundary. Output represents decoded values delivered to the handler.
const SearchLayer = defineLayer({
name: 'search',
server: {
api: {
'/api/search': ({ validate }) => {
const query = validate.query(SearchQuery);
return { filter: query.filter, page: query.page };
},
},
},
});The same schema works with validate.params, validate.query,
validate.headers, validate.json, validate.formData, and validate.value.
The body helpers are asynchronous because they consume the request body.
Current combinators are string, number, boolean, unknown,
numberFromString, booleanFromString, dateFromString, literal, union,
array, object, and optional.
optional(schema, defaultValue) makes the encoded field optional while making
the decoded field required. optional(schema) produces an optional encoded
field and a decoded value that may be undefined.
Invalid input returns HTTP 400 with a stable body:
{
"error": {
"code": "EFFUSE_VALIDATION_FAILED",
"issues": [{ "message": "...", "path": "page" }],
"message": "Request validation failed.",
"source": "query"
}
}Do not expose raw parser causes to clients. Log internal causes through server observability hooks when diagnostics are required.
Native schemas and manual validate.* calls are current and tested.
Declarative route request/response/error contracts and generated client result
types remain tracked in
#250.