Documentation status — public API reference
This page consolidates the detailed Subatom reference material supplied with the framework implementation examples. Treat the exported/public API surface as authoritative; internal implementation details are intentionally not presented as application APIs.
Context (ctx)
The ctx object encapsulates the entire HTTP exchange cycle in Subatom, acting as a unified facade wrapping the incoming request (ctx.req) and outgoing response (ctx.res).
Every route handler and controller receives ctx as its single argument. It provides schema-inferred request data getters, connection metadata, and convenient delegation methods to manipulate headers, cookies, and responses without directly touching underlying low-level abstractions.
router.get('/user/:id', {
controller: (ctx) => {
return ctx.status(200).json({
id: ctx.params.id,
userAgent: ctx.get('User-Agent'),
clientIp: ctx.ip,
});
}
});
Table of Contents
- Underlying Abstractions & Aliases
- Inferred Request Data Properties
- Request Metadata Properties
- Response Status Inspection Properties
- Request Facade Methods
- Response Facade Methods
- Context Factory (
getOrCreateContext)
Underlying Abstractions & Aliases
ctx.req / ctx.request
Points to the internal Subatom typed request abstraction (IRequest). ctx.request is an identical getter alias for ctx.req.
const nativePath = ctx.req.path;
const samePath = ctx.request.path;
ctx.res / ctx.response
Points to the Subatom response abstraction (IResponse). ctx.response is an identical getter alias for ctx.res.
ctx.res.status(200);
ctx.response.send("Hello");
Inferred Request Data Properties
Subatom leverages schema inference (supporting subatom-infer, Standard Schema, Zod, Valibot, and plain object definitions). Request data getters automatically infer their TypeScript types from the route schema.
ctx.params
Contains route parameters specified in the route path (e.g. /users/:id). Defaults to {} if no parameters exist.
// Route: /users/:id
const userId = ctx.params.id;
ctx.query
Contains key-value pairs parsed from the URL query string (e.g. ?sort=asc&limit=10). Defaults to {}.
// GET /products?sort=asc&limit=10
const { sort, limit } = ctx.query;
ctx.body
Contains the parsed incoming request body payload (JSON, form-data, or raw buffer).
router.post('/login', {
controller: (ctx) => {
const { email, password } = ctx.body;
return ctx.json({ status: "verifying" });
}
});
ctx.headers
Contains the incoming HTTP request headers dictionary as lowercase key-value pairs.
const authHeader = ctx.headers['authorization'];
ctx.cookies
Contains the parsed cookies sent by the client. Defaults to {} if no cookies were supplied.
const sessionToken = ctx.cookies['session_token'];
ctx.file / ctx.files
Provides access to uploaded files parsed during multipart request handling.
ctx.file: Represents a single uploaded file (IFileUpload | undefined).ctx.files: Represents a dictionary of uploaded files (FilesMapor schema-inferred files).
router.post('/avatar', {
middleware:[
file.single("avatar", {
storage: "memory",
allowedMimeTypes: [
"image/jpeg",
"image/png",
"image/webp",
],
})
]
controller: (ctx) => {
const avatar = ctx.file as IFileUpload | undefined;
console.log(avatar?.filename, avatar?.size);
return ctx.status(201).json({ uploaded: true });
}
});
ctx.user
A mutable property reserved for holding authenticated user details. Commonly populated by authentication middleware.
// In auth middleware:
ctx.user = { id: "usr_102", role: "admin" };
// In controller:
const currentUser = ctx.user;
ctx.locals
A mutable dictionary reserved for passing request-scoped variables across middleware and route handlers (e.g. request IDs, timings, database transactions).
ctx.locals.traceId = "trc_998127364";
ctx.locals.startedAt = Date.now();
Request Metadata Properties
ctx.ip
Returns the client's IP address (derived from connection sockets or proxy headers like X-Forwarded-For).
const clientIp = ctx.ip;
ctx.method
Returns the HTTP method of the request in uppercase (GET, POST, PUT, DELETE, etc.).
if (ctx.method === 'POST') {
// handle submission
}
ctx.path
Returns the path portion of the request URL (excluding protocol, host, and query string).
// Request: GET /api/v1/users?page=1
ctx.path; // => "/api/v1/users"
ctx.url
Returns the full relative request URL, including query parameters.
// Request: GET /api/v1/users?page=1
ctx.url; // => "/api/v1/users?page=1"
ctx.protocol
Returns the HTTP protocol string: "http" or "https".
const isSecure = ctx.protocol === "https";
ctx.secure
Boolean shorthand indicating whether the request is transmitted over TLS/HTTPS (true if ctx.protocol === "https").
if (!ctx.secure) {
return ctx.redirect(`https://${ctx.host}${ctx.url}`, 301);
}
ctx.host
Returns the host value derived from the Host HTTP header (includes hostname and port if present).
// Host: localhost:3000
ctx.host; // => "localhost:3000"
ctx.hostname
Returns the hostname portion of the Host header without the port number.
// Host: localhost:3000
ctx.hostname; // => "localhost"
ctx.session / ctx.sessionID
Provides access to the active session abstraction and unique session ID if a session middleware pipeline is attached.
const id = ctx.sessionID;
ctx.session.set('visited', true);
Response Status Inspection Properties
ctx.headersSent
Boolean property indicating whether HTTP headers have already been sent to the client.
if (!ctx.headersSent) {
ctx.status(500).send("Error");
}
ctx.writableEnded
Boolean property indicating whether res.end() has been invoked and response transmission has finished.
if (ctx.writableEnded) {
// Response completed
}
ctx.statusCode
Inspects the current numeric HTTP status code set for the response. Defaults to 200.
ctx.status(202);
console.log(ctx.statusCode); // => 202
ctx.helper
Direct facade to the Subatom standardized HTTP Response Helper (IResponseHelper). Allows invoking semantic status shortcuts (ctx.helper.success(), ctx.helper.not_found(), etc.).
return ctx.helper.created({ id: 101, created: true });
Request Facade Methods
ctx.get(headerName)
Returns the value of the specified HTTP request header. The lookup is case-insensitive.
| Parameter | Type | Description |
|---|---|---|
headerName |
string |
The header field to retrieve. |
const userAgent = ctx.get('User-Agent');
const auth = ctx.get('authorization');
ctx.accepts(...types)
Checks if the specified content types are acceptable based on the request's Accept HTTP header.
- When given a single string, returns
boolean(trueif accepted, otherwisefalse). - When given multiple strings or an array of strings, returns the best match string, or
false.
| Parameter | Type | Description |
|---|---|---|
types |
string | string[] |
MIME types or extensions to check ('json', 'text/html', 'application/json'). |
// Single string check -> boolean
if (ctx.accepts('application/json')) {
return ctx.json({ status: 'ok' });
}
// Multiple arguments -> returns best matching string or false
const match = ctx.accepts('text/html', 'application/json');
// Array parameter -> returns best matching string or false
const bestFormat = ctx.accepts(['text/plain', 'application/json']);
Response Facade Methods
Context delegates standard response methods directly to ctx.res, enabling clean chaining and concise syntax.
ctx.status(code)
Sets the HTTP status code for the response. Returns this for chaining.
| Parameter | Type | Description |
|---|---|---|
code |
number |
A 3-digit standard HTTP status code. |
ctx.status(404).send('Not Found');
ctx.set(name, [value])
Sets the outgoing response HTTP header name to value. To set multiple headers at once, pass an object.
Aliases: ctx.header(), ctx.setHeader().
| Parameter | Type | Description |
|---|---|---|
name |
string | Record<string, string | string[]> |
Header name string or dictionary of header names and values. |
value |
string | string[] |
Header value or array of values (if name is a string). |
// Single header
ctx.set('X-Custom-Header', 'Subatom');
// Method aliases
ctx.header('X-App-Version', '1.0.0');
ctx.setHeader('X-Trace-ID', 'trc_12345');
// Multiple headers
ctx.set({
'Cache-Control': 'no-store',
'X-Powered-By': 'Subatom Framework'
});
ctx.type(type)
Sets the Content-Type response header to the specified MIME type.
Alias: ctx.contentType().
| Parameter | Type | Description |
|---|---|---|
type |
string |
MIME type string (e.g. 'application/json', 'text/html'). |
ctx.type('application/json');
ctx.contentType('application/json; charset=utf-8');
ctx.cookie(name, value, [options])
Sets a cookie with the specified name, value, and options. Returns this for chaining.
| Parameter | Type | Description |
|---|---|---|
name |
string |
Name of the cookie. |
value |
string |
Value string of the cookie. |
options |
CookieOptions |
(Optional) Cookie configuration options (httpOnly, secure, sameSite, maxAge, path, domain, expires). |
ctx.cookie('session_token', 'xyz123', {
httpOnly: true,
secure: true,
sameSite: 'Lax',
maxAge: 3600000,
path: '/'
});
ctx.clearCookie(name, [options])
Clears the cookie specified by name. The path and domain options must match the options used when the cookie was set.
| Parameter | Type | Description |
|---|---|---|
name |
string |
Name of the cookie to remove. |
options |
CookieOptions |
(Optional) Options specifying path and domain. |
ctx.clearCookie('session_token', { path: '/' });
ctx.send([body])
Sends the HTTP response payload. The body can be a string, Buffer, Uint8Array, or object (which automatically delegates to ctx.json()).
| Parameter | Type | Description |
|---|---|---|
body |
string | Buffer | Uint8Array | object |
(Optional) The payload to transmit. |
ctx.send('Hello from Subatom Context');
ctx.json(data)
Sends a JSON response with Content-Type: application/json. Returns this.
| Parameter | Type | Description |
|---|---|---|
data |
unknown |
Object, array, or serializable value converted using JSON.stringify(). |
return ctx.status(200).json({ status: "ok", data: [1, 2, 3] });
ctx.html(htmlContent)
Sends an HTML response with Content-Type: text/html; charset=utf-8. Returns this.
| Parameter | Type | Description |
|---|---|---|
htmlContent |
string |
HTML markup string. |
return ctx.html('<h1>Welcome to Subatom</h1>');
ctx.redirect(url, [statusCode])
Redirects the client to the specified destination URL with an HTTP status code (defaults to 302 Found).
| Parameter | Type | Description |
|---|---|---|
url |
string |
Destination URL path. |
statusCode |
number |
(Optional) HTTP status code. Defaults to 302. |
router.get('/old-dashboard', {
controller: (ctx) => {
return ctx.redirect('/dashboard', 301);
}
});
Prefix Note: If your router is mounted with a route prefix (e.g.
/api/v1), provide the full URL path:return ctx.redirect('/api/v1/dashboard', 302);
ctx.attachment([filename])
Sets the HTTP Content-Disposition header to "attachment". If filename is given, it sets the filename attribute and configures the Content-Type header based on extension.
| Parameter | Type | Description |
|---|---|---|
filename |
string |
(Optional) Recommended filename for download. |
ctx.attachment('monthly-invoice.pdf');
ctx.send(pdfBuffer);
ctx.sendFile(filePath, [options])
Transfers a file located at filePath inline. Sets Content-Type automatically based on file extension.
| Parameter | Type | Description |
|---|---|---|
filePath |
string |
Absolute or relative path to the file. |
options |
SendFileOptions |
(Optional) Options such as root (security boundary) and contentType. |
const file = path.resolve('./assets/avatar.png');
ctx.sendFile(file);
ctx.download(filePath, [filename], [options])
Transfers the file at filePath as a forced attachment download.
| Parameter | Type | Description |
|---|---|---|
filePath |
string |
Absolute or relative path to file. |
filename |
string |
(Optional) The downloaded filename presented to the client. |
options |
DownloadOptions |
(Optional) Download configurations (root, contentType). |
const reportPath = path.resolve('./reports/report.csv');
ctx.download(reportPath, 'annual-report.csv');
ctx.stream(readableStream)
Pipes a Node.js Readable stream to the client and returns a Promise<void>. Stream errors are caught automatically to prevent unhandled process crashes.
| Parameter | Type | Description |
|---|---|---|
readableStream |
NodeJS.ReadableStream |
Source readable stream to pipe. |
import { Readable } from 'node:stream';
router.get('/stream-data', {
controller: async (ctx) => {
const stream = Readable.from(['Chunk 1\n', 'Chunk 2\n']);
await ctx.stream(stream);
}
});
ctx.format(handlers, [requestHeaders])
Performs content negotiation based on the Accept request header. Matches against the provided MIME handler callbacks.
| Parameter | Type | Description |
|---|---|---|
handlers |
FormatHandlers |
Mapping of content types ('text/plain', 'text/html', 'application/json', 'default') to handlers. |
requestHeaders |
Record<string, ...> |
(Optional) Custom headers to evaluate instead of ctx.req.headers. |
router.get('/feed', {
controller: (ctx) => {
return ctx.format({
'text/plain': () => {
ctx.send('text format response');
},
'text/html': () => {
ctx.html('<p>html format response</p>');
},
'application/json': () => {
ctx.json({ format: 'json' });
},
default: () => {
ctx.status(406).send('Not Acceptable');
}
});
}
});
ctx.end([chunk])
Immediately ends the response process, bypassing higher-level response formatters.
| Parameter | Type | Description |
|---|---|---|
chunk |
unknown |
(Optional) Final chunk or payload to write before ending. |
ctx.status(200);
ctx.end("Stream finalized");
Context Factory (getOrCreateContext)
Subatom internally maintains a single instance of Context per request using a symbol key on req (Symbol.for("subatom.context")). You can obtain or instantiate the Context using the factory utility:
import { getOrCreateContext } from 'subatom';
const ctx = getOrCreateContext(req, res);
If a Context instance was already created earlier in the request lifecycle (e.g. by prior middleware), getOrCreateContext returns the existing instance without re-instantiation.
License
MIT © Kunal Chandra Das — Subatom