Skip to content

Transforms

Transforms mutate request/response shape and validate payloads as they move through the pipeline.

PolicyPriorityPurpose
cors5Apply CORS behavior (simple + preflight).
overrideMethod5POST method tunneling via override header.
requestTransform50Rename/set/remove request headers.
assignAttributes50Set context attributes (c.set).
assignContent50Inject fields into JSON request/response bodies.
requestValidation10Pluggable request validation (sync/async).
jsonValidation10JSON parse + optional custom validator.
responseTransform92Rename/set/remove response headers.

Wraps Hono CORS middleware as a policy.

import { cors } from "@homegrower-club/stoma";
interface CorsConfig {
origins?: string | string[] | ((origin: string) => boolean); // default: "*"
methods?: string[];
allowHeaders?: string[];
exposeHeaders?: string[];
maxAge?: number; // default from Hono behavior
credentials?: boolean; // default: false
skip?: (c: Context) => boolean | Promise<boolean>;
}

Apply method override on POST requests only.

import { overrideMethod } from "@homegrower-club/stoma";
interface OverrideMethodConfig {
header?: string; // default: "X-HTTP-Method-Override"
allowedMethods?: string[]; // default: ["GET", "PUT", "PATCH", "DELETE"]
skip?: (c: Context) => boolean | Promise<boolean>;
}

Invalid overrides return 400 invalid_method_override.


Rename, set, and remove request headers before upstream dispatch.

import { requestTransform } from "@homegrower-club/stoma";
interface RequestTransformConfig {
renameHeaders?: Record<string, string>;
setHeaders?: Record<string, string>;
removeHeaders?: string[];
skip?: (c: Context) => boolean | Promise<boolean>;
}

Operation order: rename -> set -> remove.


Rename, set, and remove response headers after downstream runs.

import { responseTransform } from "@homegrower-club/stoma";
interface ResponseTransformConfig {
renameHeaders?: Record<string, string>;
setHeaders?: Record<string, string>;
removeHeaders?: string[];
skip?: (c: Context) => boolean | Promise<boolean>;
}

Operation order: rename -> set -> remove.


Attach key/value values to request context.

import { assignAttributes } from "@homegrower-club/stoma";
interface AssignAttributesConfig {
attributes: Record<string, string | ((c: Context) => string | Promise<string>)>;
skip?: (c: Context) => boolean | Promise<boolean>;
}

Downstream readers use c.get(key).


Inject/override JSON fields in request and/or response bodies.

import { assignContent } from "@homegrower-club/stoma";
interface AssignContentConfig {
request?: Record<string, unknown | ((c: Context) => unknown | Promise<unknown>)>;
response?: Record<string, unknown | ((c: Context) => unknown | Promise<unknown>)>;
contentTypes?: string[]; // default: ["application/json"]
skip?: (c: Context) => boolean | Promise<boolean>;
}

Only matching content types are modified.


Pluggable request body validation (sync or async), with optional detailed errors.

import { requestValidation } from "@homegrower-club/stoma";
interface RequestValidationConfig {
validate?: (body: unknown) => boolean | { valid: boolean; errors?: string[] };
validateAsync?: (body: unknown) => Promise<boolean | { valid: boolean; errors?: string[] }>;
contentTypes?: string[]; // default: ["application/json"]
errorMessage?: string; // default: "Request validation failed"
skip?: (c: Context) => boolean | Promise<boolean>;
}

Notes:

  • validateAsync takes precedence over validate.
  • Invalid JSON or failed validation returns 400 validation_failed.

JSON-specific validation policy:

  • Always checks parseable JSON for matching content types.
  • Optionally applies a user validate function.
import { jsonValidation } from "@homegrower-club/stoma";
interface JsonValidationConfig {
validate?: (body: unknown) => { valid: boolean; errors?: string[] } | Promise<{ valid: boolean; errors?: string[] }>;
contentTypes?: string[]; // default: ["application/json"]
rejectStatus?: number; // default: 422
errorDetail?: boolean; // default: true
skip?: (c: Context) => boolean | Promise<boolean>;
}

Errors use validation_failed with configurable status (422 by default).


FeaturerequestValidationjsonValidation
Default status code400422
Built-in empty JSON body errorno explicit empty-body branchyes (Request body is empty)
Validator return shapeboolean or { valid, errors }{ valid, errors }
Async validator optionvalidateAsync fieldasync function through validate

import {
cors,
overrideMethod,
requestTransform,
assignAttributes,
assignContent,
requestValidation,
responseTransform,
} from "@homegrower-club/stoma";
[
cors({ origins: ["https://app.example.com"], credentials: true }),
overrideMethod(),
assignAttributes({ attributes: { tenant: (c) => c.req.header("x-tenant") ?? "default" } }),
requestValidation({
validate: (body) => ({ valid: typeof body === "object" && body !== null, errors: ["Body must be object"] }),
}),
assignContent({ request: { gateway: "stoma" } }),
requestTransform({ setHeaders: { "x-api-version": "2026-01-01" } }),
responseTransform({ removeHeaders: ["server"] }),
]