Skip to content

send

The terminal response writer in ergo’s two-accumulator model. Called once by handler() (or ergo-router’s auto-wrap) after the pipeline completes. Reads from both the response accumulator and domain accumulator to serialize the HTTP response.

send is not placed inside the pipeline — it runs after the pipeline via handler().

Pipeline stage: Post-pipeline (called by handler)

import { send } from "@centralping/ergo";
OptionTypeDefaultDescription
prettifybooleanfalsePretty-print JSON output
varystring[]['Accept']Vary header values to append
etagbooleantrueGenerate ETags and evaluate conditional headers
preferbooleanfalseRead domainAcc.prefer for RFC 7240 return=minimal / return=representation. When true, appends Prefer to the Vary header
paginatebooleanfalseRead domainAcc.paginate and responseAcc.paginate to auto-generate RFC 8288 Link headers and X-Total-Count for paginated responses
envelopeboolean | functionfalseWrap 2xx Object bodies in a response envelope
errorFormatterfunctionCustom error body formatter for 4xx/5xx responses. Receives the RFC 9457 Problem Details object and {requestId, statusCode, method} context. Return value becomes the response body as application/json instead of application/problem+json
ValueBehavior
falseNo envelope (default)
trueBuilt-in { id, status, data, count? }id is read from the x-request-id response header
functionCustom (body, ctx) => wrappedBody

Response accumulator: statusCode, body, headers, detail, retryAfter, instance, location, lastModified, type, paginate (pagination response metadata: total, nextCursor, prevCursor)

Domain accumulator: cookies (cookie jar → Set-Cookie), prefer (parsed Prefer header), paginate (parsed pagination parameters)

Body TypeContent-TypeBehavior
null / undefinedDefault status text (empty for 204/304)
stringAuto-detected HTML or textWritten as-is
Uint8Arrayapplication/octet-streamWritten as binary
StreamPiped to response
Objectapplication/jsonJSON-serialized (respects prettify)

Error bodies are automatically formatted as RFC 9457 Problem Details from the response accumulator’s statusCode, detail, retryAfter, instance, and any extension members.

StatusCondition
304 Not ModifiedIf-None-Match weak-matches the ETag, or If-Modified-Since and resource not modified
412 Precondition FailedIf-Match fails on unsafe methods, or If-Unmodified-Since fails
204 No ContentPrefer: return=minimal on 2xx responses (200 → 204)

Return lastModified on the response accumulator to set the Last-Modified header and enable date-based conditional request evaluation. The value can be a Date or a date string — unparseable values are silently ignored (no header set, no conditional evaluation).

import { handler, compose } from "@centralping/ergo";
const pipeline = compose(
async (req, res, acc) => {
const todo = await db.findById("42");
return {
response: {
statusCode: 200,
body: todo,
lastModified: todo.updatedAt,
},
};
},
);
const server = http.createServer(handler(pipeline));
// GET /todos/42
// → 200 OK
// → Last-Modified: Thu, 05 Jun 2025 12:00:00 GMT

When a client sends the Last-Modified value back in an If-Modified-Since header, send() automatically returns 304 Not Modified with no body if the resource has not changed. Dates are compared at second granularity.

GET /todos/42
If-Modified-Since: Thu, 05 Jun 2025 12:00:00 GMT
→ 304 Not Modified (no body)

For unsafe methods (PUT, PATCH, DELETE), send() evaluates If-Unmodified-Since as a write-protection guard. If the resource was modified after the condition date, the request is rejected with 412 Precondition Failed.

import { handler, compose, body } from "@centralping/ergo";
const pipeline = compose(
{fn: body(), setPath: "body"},
async (req, res, acc) => {
const todo = await db.findAndUpdate("42", acc.body.parsed);
return {
response: {
statusCode: 200,
body: todo,
lastModified: todo.updatedAt,
},
};
},
);
const server = http.createServer(handler(pipeline));
// PUT /todos/42
// If-Unmodified-Since: Thu, 05 Jun 2025 11:00:00 GMT
// (resource modified at 12:00:00 — after the condition date)
// → 412 Precondition Failed
import { handler, compose, send } from "@centralping/ergo";
const pipeline = compose(
(req, res, acc) => ({
response: { statusCode: 200, body: { hello: "world" } },
}),
);
const server = http.createServer(
handler(pipeline, { etag: true, prettify: true }),
);
  • Pagination — End-to-end offset and cursor pagination with auto-generated Link headers

See the auto-generated send API docs.