Skip to content

Server Request Schemas

Chris Michael edited this page Jul 18, 2026 · 2 revisions

Effuse

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.

Define A Schema

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.

Validate A Request

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.

Combinators

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.

Validation Errors

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.

Current Boundary

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.

Clone this wiki locally