Transforms
Transforms mutate request/response shape and validate payloads as they move through the pipeline.
Policy Summary
Section titled “Policy Summary”| Policy | Priority | Purpose |
|---|---|---|
cors | 5 | Apply CORS behavior (simple + preflight). |
overrideMethod | 5 | POST method tunneling via override header. |
requestTransform | 50 | Rename/set/remove request headers. |
assignAttributes | 50 | Set context attributes (c.set). |
assignContent | 50 | Inject fields into JSON request/response bodies. |
requestValidation | 10 | Pluggable request validation (sync/async). |
jsonValidation | 10 | JSON parse + optional custom validator. |
responseTransform | 92 | Rename/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>;}overrideMethod
Section titled “overrideMethod”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.
requestTransform
Section titled “requestTransform”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.
responseTransform
Section titled “responseTransform”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.
assignAttributes
Section titled “assignAttributes”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).
assignContent
Section titled “assignContent”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.
requestValidation
Section titled “requestValidation”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:
validateAsynctakes precedence overvalidate.- Invalid JSON or failed validation returns
400validation_failed.
jsonValidation
Section titled “jsonValidation”JSON-specific validation policy:
- Always checks parseable JSON for matching content types.
- Optionally applies a user
validatefunction.
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).
requestValidation vs jsonValidation
Section titled “requestValidation vs jsonValidation”| Feature | requestValidation | jsonValidation |
|---|---|---|
| Default status code | 400 | 422 |
| Built-in empty JSON body error | no explicit empty-body branch | yes (Request body is empty) |
| Validator return shape | boolean or { valid, errors } | { valid, errors } |
| Async validator option | validateAsync field | async function through validate |
Example
Section titled “Example”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"] }),]