HTTP Server

Send: Structured HTTP Response Utility

A strongly-typed, opinionated API for standardising every JSON response sent from XyPriss — success or error.

Send centralises status code resolution, response body construction, and output flushing into a single interface. Every method produces a JSON object conforming to the IResTemplate contract, guaranteeing predictability for API consumers.

Why Send?
Without a unified response layer, large applications drift into ad-hoc patterns (inconsistent shapes, missing fields, duplicated logic). Send eliminates this by enforcing a single contract across every handler.

Response Body Contract

Every response produced by Send conforms to IResTemplate:

typescript
{
  success: boolean;
  message: string;
  serverName?: string;
  data?: unknown;
  details: {
    error: string;
    errorCode: string;
    statusCode: number;
  };
}

200 OK Success

json
{
  "success": true,
  "message": "User fetched successfully.",
  "serverName": "my-api",
  "data": { "id": 1, "name": "Alice" },
  "details": { "error": "OK", "errorCode": "SOK", "statusCode": 200 }
}

404 Not Found

json
{
  "success": false,
  "message": "No user found with id '42'.",
  "serverName": "my-api",
  "details": { "error": "Not Found", "errorCode": "ENOT", "statusCode": 404 }
}

Constructor

typescript
new Send(res: XyPrisResponse, configs?: Partial<{
  statusCode: Partial<ISeConfigs>;
  includeServerName: boolean;
}>)

The server name is read from __sys__.vars.__name__ at construction time and remains constant for the lifetime of the instance.

API Reference

2xx — Success

send.ok(message?, data?)

200 OK — successful GET, PUT, PATCH, DELETE with body.

typescript
send.ok("User fetched.", { id: 1 });

send.created(message?, data?)

201 Created — after persisting a new resource.

typescript
send.created("User created.", { id: 42 });

send.accepted(message?, data?)

202 Accepted — request received, processing async.

typescript
send.accepted("Export started.", { jobId: "abc" });

send.noContent()

204 No Content — no body. Complies with RFC 7231.

typescript
send.noContent();

3xx — Redirection

send.movedPermanently(message?, data?)

301 — clients should update references.

typescript
send.movedPermanently("Moved.", { location: "/v2/users" });

send.found(message?, data?)

302 — temporary redirect.

typescript
send.found("Redirecting.", { location: "/login" });

send.notModified()

304 — no body. Use with conditional requests.

typescript
send.notModified();

4xx — Client Errors

send.badRequest(message?, data?)

400 — malformed requests, validation failures.

typescript
send.badRequest("The email field is required.");

send.unauthorized(message?, data?)

401 — missing or expired auth credentials.

typescript
send.unauthorized("Token expired.");

send.forbidden(message?, data?)

403 — authenticated but lacks permissions.

typescript
send.forbidden("Admin role required.", { requiredRole: "admin" });

send.notFound(message?, data?)

404 — resource does not exist.

typescript
send.notFound("Invoice #INV-1042 does not exist.");

send.methodNotAllowed(message?, data?)

405 — HTTP method not supported.

typescript
send.methodNotAllowed("Only GET allowed.", { allowedMethods: ["GET"] });

send.conflict(message?, data?)

409 — request conflicts with current state.

typescript
send.conflict("Email already registered.");

send.unprocessableEntity(message?, data?)

422 — valid syntax but semantic errors.

typescript
send.unprocessableEntity("Birth date must be in the past.");

send.tooManyRequest(message?, data?)

429 — rate limit exceeded.

typescript
send.tooManyRequest("Rate limit.", { retryAfter: 30 });

5xx — Server Errors

send.internalError(message?, data?)

500 — unexpected server failure. Never expose stack traces.

typescript
send.internalError("An unexpected error occurred.");

send.notImplemented(message?, data?)

501 — functionality not yet supported.

typescript
send.notImplemented("PATCH is not supported.");

send.badGateway(message?, data?)

502 — invalid response from upstream.

typescript
send.badGateway("Provider returned unexpected response.");

send.serviceUnavailable(message?, data?)

503 — temporary overload or maintenance.

typescript
send.serviceUnavailable("Maintenance until 06:00 UTC.", { retryAfter: "2026-06-01T06:00:00Z" });

send.gatewayTimeout(message?, data?)

504 — upstream did not respond in time.

typescript
send.gatewayTimeout("Database timed out.", { service: "payments-api", timeoutMs: 5000 });

Usage Examples

Basic Setup

Instantiate Send at the beginning of a route handler:

typescript
import { Send } from "../utils/Send";

app.get("/users/:id", (req, res) => {
  const send = new Send(res);

  const user = db.users.findById(req.params.id);
  if (!user) {
    return send.notFound(`No user found with id '${req.params.id}'.`);
  }

  send.ok("User fetched successfully.", user);
});

Success, Client Error, and Server Error Patterns

typescript
const send = new Send(res);

// Success
send.ok("Product retrieved.", product);
send.created("Order placed.", { orderId: "ORD-9821" });
send.accepted("Report started.", { jobId: "JOB-4412" });
send.noContent();

// Client errors
send.badRequest("Quantity must be positive.");
send.unauthorized("Session expired.");
send.conflict("Email already registered.");
send.tooManyRequest("Limit reached.", { retryAfter: 30 });

// Server errors
try {
  await processPayment(order);
  send.ok("Payment processed.", { transactionId: "TXN-7731" });
} catch (err) {
  logger.error(err);
  send.internalError("Payment processing failed.");
}

Custom Configuration

Override status codes or hide the server name:

typescript
const send = new Send(res, {
  statusCode: { NOT_FOUND: 404, TOO_MANY_REQUEST: 429 },
  includeServerName: false
});

send.ok("Fetched.", payload);
// Response body will not contain `serverName`

Design Principles

  • Single source of truth for response shape. The IResTemplate contract is enforced uniformly across all endpoints.
  • Explicit over implicit. Each HTTP status has its own named method. No generic send.status(code, ...) escape hatch.
  • No body on no-body statuses. noContent() and notModified() call res.end() directly, complying with RFC 7231.
  • Short, stable error codes. The errorCode field provides a compact identifier for monitoring dashboards and log parsers.
  • Defence in depth on 5xx messages. The documentation explicitly reminds developers never to expose raw stack traces in the message argument.

Integration with XyPriss

Send is a first-party utility. It depends on XyPrisResponse and the global __sys__ object. It does not introduce any external dependencies and is intended to be instantiated per-request inside route handlers.

typescript
import { Send } from "../utils/Send";
import type { XyPrisRequest, XyPrisResponse } from "../server/routing";

export async function getUserById(req: XyPrisRequest, res: XyPrisResponse) {
  const send = new Send(res);
  // ... handler logic
}
Response Control

Customise unhandled route behaviour with custom status codes and handlers.