CResponse
The CResponse class represents an HTTP response with automatic body serialization, cookie handling, and header management. It provides static helpers for common response patterns like redirects, file streaming, and Server-Sent Events.
Contents
Usage
Basic response
import { C } from "@ozanarslan/corpus";
new C.Route("/hello", () => {
return new C.Response("Hello World");
});
With status and headers
new C.Route("/created", () => {
return new C.Response(
{ id: 1 },
{
status: C.Status.CREATED,
headers: { [C.CommonHeaders.Location]: "/items/1" },
},
);
});
Setting cookies
The following is the recommended pattern because CResponse init can also receive another CResponse instance and typescript doesn't do a great job differentiating an object with a class.
new C.Route("/login", (c) => {
c.res.cookies.set({
name: "session",
value: "abc123",
httpOnly: true,
secure: true,
});
return { success: true };
});
Accessing the native response
const cres = new C.Response("data");
cres.response; // Returns native Web API Response
Constructor Parameters
data (optional)
CResponseBody<R>
The response body. Automatically serialized based on type. See Body Serialization.
init (optional)
CResponseInit | CResponse
Response options or another CResponse to copy from.
type CResponseInit = {
cookies?: CookiesInit;
headers?: CHeadersInit;
status?: Status;
statusText?: string;
};
Properties
| Property | Type | Description |
|---|---|---|
| body | BodyInit |
Resolved and serialized body |
| headers | CHeaders |
Response headers |
| status | Status |
HTTP status code |
| statusText | string |
HTTP status text |
| cookies | Cookies |
Response cookies |
| response | Response |
Getter returning native Web API Response |
Static Methods
redirect
static redirect(url: string | URL, init?: CResponseInit): CResponse
Creates a redirect response. Defaults to 302 Found.
return C.Response.redirect("/new-path");
return C.Response.redirect("/new-path", {
status: C.Status.MOVED_PERMANENTLY,
});
permanentRedirect
static permanentRedirect(url: string | URL, init?: Omit<CResponseInit, "status">): CResponse
301 Moved Permanently redirect.
temporaryRedirect
static temporaryRedirect(url: string | URL, init?: Omit<CResponseInit, "status">): CResponse
307 Temporary Redirect.
seeOther
static seeOther(url: string | URL, init?: Omit<CResponseInit, "status">): CResponse
303 See Other (redirect with GET).
sse
static sse(source: SseSource, init?: Omit<CResponseInit, "status">, retry?: number): CResponse
Server-Sent Events stream.
return C.Response.sse((send) => {
const interval = setInterval(() => {
send({ data: { time: Date.now() }, event: "tick" });
}, 1000);
return () => clearInterval(interval); // cleanup
});
ndjson
static ndjson(source: NdjsonSource, init?: Omit<CResponseInit, "status">): CResponse
Newline-delimited JSON stream.
return C.Response.ndjson((send) => {
for (const item of largeDataset) {
send(item);
}
});
streamFile
static async streamFile(filePath: string, disposition?: "attachment" | "inline", init?: Omit<CResponseInit, "status">): Promise<CResponse<ReadableStream>>
Stream a file from disk. Uses Content-Type from file extension. Defaults to attachment disposition.
return await C.Response.streamFile("assets/video.mp4", "inline");
Throws CError with 404 if file not found.
file
static async file(filePath: string, init?: CResponseInit): Promise<CResponse<string>>
Read entire file into memory as string. Sets Content-Length header.
return await C.Response.file("assets/doc.txt");
Throws CError with 404 if file not found.
Body Serialization
The body is automatically serialized based on its type:
| Type | Serialization | Content-Type |
|---|---|---|
null / undefined |
Empty string | text/plain |
Primitives (string, number, boolean, bigint) |
String(data) |
text/plain |
Date |
toISOString() |
text/plain |
| Plain objects / arrays | JSON.stringify() |
application/json |
ArrayBuffer |
As-is | application/octet-stream |
Blob |
As-is | Blob's type or application/octet-stream |
FormData |
As-is | multipart/form-data |
URLSearchParams |
As-is | application/x-www-form-urlencoded |
ReadableStream |
As-is | Set manually via headers |
| Custom class instances | String(data) (calls .toString()) |
text/plain |
Status Enum
Commonly used HTTP status codes.
type Status = OrNumber<ValueOf<typeof Status>>;
const Status = {
/** --- 1xx Informational --- */
/** Continue: Request received, please continue */
CONTINUE: 100,
/** Switching Protocols: Protocol change request approved */
SWITCHING_PROTOCOLS: 101,
/** Processing (WebDAV) */
PROCESSING: 102,
/** Early Hints */
EARLY_HINTS: 103,
/** --- 2xx Success --- */
/** OK: Request succeeded */
OK: 200,
/** Created: Resource created */
CREATED: 201,
/** Accepted: Request accepted but not completed */
ACCEPTED: 202,
/** Non-Authoritative Information */
NON_AUTHORITATIVE_INFORMATION: 203,
/** No Content: Request succeeded, no body returned */
NO_CONTENT: 204,
/** Reset Content: Clear form or view */
RESET_CONTENT: 205,
/** Partial Content: Partial GET successful (e.g. range requests) */
PARTIAL_CONTENT: 206,
/** Multi-Status (WebDAV) */
MULTI_STATUS: 207,
/** Already Reported (WebDAV) */
ALREADY_REPORTED: 208,
/** IM Used (HTTP Delta encoding) */
IM_USED: 226,
/** --- 3xx Redirection --- */
/** Multiple Choices */
MULTIPLE_CHOICES: 300,
/** Moved Permanently: Resource moved to a new URL */
MOVED_PERMANENTLY: 301,
/** Found: Resource temporarily under different URI */
FOUND: 302,
/** See Other: Redirect to another URI using GET */
SEE_OTHER: 303,
/** Not Modified: Cached version is still valid */
NOT_MODIFIED: 304,
/** Use Proxy: Deprecated */
USE_PROXY: 305,
/** Temporary Redirect: Resource temporarily at another URI */
TEMPORARY_REDIRECT: 307,
/** Permanent Redirect: Resource permanently at another URI */
PERMANENT_REDIRECT: 308,
/** --- 4xx Client Errors --- */
/** Bad Request: Malformed request */
BAD_REQUEST: 400,
/** Unauthorized: Missing or invalid auth credentials */
UNAUTHORIZED: 401,
/** Payment Required: Reserved for future use */
PAYMENT_REQUIRED: 402,
/** Forbidden: Authenticated but no permission */
FORBIDDEN: 403,
/** Not Found: Resource does not exist */
NOT_FOUND: 404,
/** Method Not Allowed: HTTP method not allowed */
METHOD_NOT_ALLOWED: 405,
/** Not Acceptable: Response not acceptable by client */
NOT_ACCEPTABLE: 406,
/** Proxy Authentication Required */
PROXY_AUTHENTICATION_REQUIRED: 407,
/** Request Timeout: Server timeout waiting for client */
REQUEST_TIMEOUT: 408,
/** Conflict: Request conflict (e.g. duplicate resource) */
CONFLICT: 409,
/** Gone: Resource is no longer available */
GONE: 410,
/** Length Required: Missing Content-Length header */
LENGTH_REQUIRED: 411,
/** Precondition Failed */
PRECONDITION_FAILED: 412,
/** Payload Too Large */
PAYLOAD_TOO_LARGE: 413,
/** URI Too Long */
URI_TOO_LONG: 414,
/** Unsupported Media Type */
UNSUPPORTED_MEDIA_TYPE: 415,
/** Range Not Satisfiable */
RANGE_NOT_SATISFIABLE: 416,
/** Expectation Failed */
EXPECTATION_FAILED: 417,
/** I'm a teapot: Joke response for coffee machines */
IM_A_TEAPOT: 418,
/** Misdirected Request: Sent to the wrong server */
MISDIRECTED_REQUEST: 421,
/** Unprocessable Entity (WebDAV) */
UNPROCESSABLE_ENTITY: 422,
/** Locked (WebDAV) */
LOCKED: 423,
/** Failed Dependency (WebDAV) */
FAILED_DEPENDENCY: 424,
/** Too Early: Request might be replayed */
TOO_EARLY: 425,
/** Upgrade Required */
UPGRADE_REQUIRED: 426,
/** Precondition Required */
PRECONDITION_REQUIRED: 428,
/** Too Many Requests: Rate limiting */
TOO_MANY_REQUESTS: 429,
/** Request Header Fields Too Large */
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
/** Unavailable For Legal Reasons */
UNAVAILABLE_FOR_LEGAL_REASONS: 451,
/** --- 5xx Server Errors --- */
/** Internal Server Error: Unhandled server error */
INTERNAL_SERVER_ERROR: 500,
/** Not Implemented: Endpoint/method not implemented */
NOT_IMPLEMENTED: 501,
/** Bad Gateway: Invalid response from upstream server */
BAD_GATEWAY: 502,
/** Service Unavailable: Server temporarily overloaded/down */
SERVICE_UNAVAILABLE: 503,
/** Gateway Timeout: No response from upstream server */
GATEWAY_TIMEOUT: 504,
/** HTTP Version Not Supported */
HTTP_VERSION_NOT_SUPPORTED: 505,
/** Variant Also Negotiates */
VARIANT_ALSO_NEGOTIATES: 506,
/** Insufficient Storage (WebDAV) */
INSUFFICIENT_STORAGE: 507,
/** Loop Detected (WebDAV) */
LOOP_DETECTED: 508,
/** Not Extended */
NOT_EXTENDED: 510,
/** Network Authentication Required */
NETWORK_AUTHENTICATION_REQUIRED: 511,
} as const;