HttpAdapter
HttpAdapter is the abstract base class for all HTTP platform adapters. It manages the interceptor chain, base path, scope, and request processing — including context creation, parsing, dispatch, response serialization, and bundle handling.
import { HttpAdapter } from '@opra/http';
Extends: PlatformAdapter
You do not instantiate HttpAdapter directly. Extend ExpressAdapter or implement your own platform adapter subclass.
Properties
| Property | Type | Description |
|---|---|---|
transform | 'http' | Always 'http'. Identifies the transport type. |
basePath | string | URL prefix prepended to all OPRA routes. Defaults to '/'. |
scope | string | undefined | Validation scope applied to every request and response. |
interceptors | (InterceptorFunction | IHttpInterceptor)[] | Mutable interceptor chain executed on every request. |
api | HttpApi | The HTTP API definition from the document. Shorthand for document.getHttpApi(). |
Abstract methods
handleRawRequest
abstract handleRawRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>
Entry point for the platform adapter implementation. Subclasses (e.g. ExpressAdapter) implement this to receive raw Node.js request/response objects, resolve the matching controller and operation, and call handleRequest with the constructed context.
Methods
createContext
createContext(
req: http.IncomingMessage,
res: http.OutgoingMessage,
args?: {
controller?: HttpController;
controllerInstance?: any;
operation?: HttpOperation;
operationHandler: Function;
}
): Promise<HttpContext>
Creates an HttpContext from raw Node.js request/response objects. Upgrades req to an HttpRequest and res to an HttpResponse, then emits the 'create-context' event before returning.
Called by handleRawRequest implementations. You rarely need to call this directly.
handleRequest
handleRequest(context: HttpContext): Promise<void>
Main request processing pipeline. Sets OPRA response headers, runs parseRequest, fires the 'request' event, executes the interceptor chain, calls the operation handler via sendResponse, and emits 'finish'. On error, wraps the exception with wrapException and sends an error response.
handleBundle
handleBundle(bundle: HttpBundle): Promise<void>
Processes a bundle request — a multipart/mixed request where each part is a complete HTTP sub-request. Each sub-request is parsed and dispatched independently via handleRawRequest, and the sub-responses are collected and returned as a single multipart/mixed response. Part-level X-Request-Id headers are preserved in the response parts for correlation.
Throws BadRequestError if the request Content-Type is not multipart/mixed.
// Bundle requests are typically handled transparently by ExpressAdapter.
// Each part of the multipart body is a raw HTTP request:
// POST /api/$bundle HTTP/1.1
// Content-Type: multipart/mixed; boundary=---boundary
//
// -----boundary
// Content-Type: application/http
// X-Request-Id: req-1
//
// GET /api/customers HTTP/1.1
// ...
parseRequest
parseRequest(context: HttpContext): Promise<void>
Decodes all declared parameters (cookies, headers, path, query) and validates the Content-Type against the operation's .RequestContent() declaration. Sets the default response status code from the first declared 2xx response.
sendResponse
sendResponse(context: HttpContext, responseValue?: any): Promise<void>
Serializes and sends the response. Validates and encodes the body against the declared HttpOperationResponse type. Handles OperationResult wrapping, content-type negotiation, composition-based payload shaping (e.g. Entity.FindMany), and error fallback.
sendDocumentSchema
sendDocumentSchema(context: HttpContext): Promise<void>
Responds with the full ApiDocument serialized as JSON. Used by the GET {basePath}/$schema endpoint. Supports an optional ?id= query parameter to return a sub-document.
Interfaces
HttpAdapter.Options
| Option | Type | Default | Description |
|---|---|---|---|
basePath | string | '/' | URL prefix for all OPRA routes. |
scope | string | '*' | — | Validation scope applied to every request and response. '*' disables scope filtering. |
interceptors | (InterceptorFunction | IHttpInterceptor)[] | [] | Interceptor chain executed on every request. |
HttpAdapter.ResponseArgs
Internal shape used to carry resolved response metadata before the response is sent.
| Property | Type | Description |
|---|---|---|
statusCode | number | HTTP status code to send. |
contentType | string | undefined | Resolved Content-Type value. |
operationResponse | HttpOperationResponse | undefined | The matched HttpOperationResponse declaration. |
body | any | The response body after encoding. |
projection | string[] | '*' | undefined | Field projection applied during encoding. |
HttpAdapter.IHttpInterceptor
type IHttpInterceptor = {
intercept(context: HttpContext, next: NextCallback): Promise<void>;
};
Class-based interceptor interface. Implement intercept to wrap request processing.
HttpAdapter.InterceptorFunction
type InterceptorFunction = (context: HttpContext, next: NextCallback) => Promise<void>;
Function-based interceptor. Equivalent to IHttpInterceptor['intercept'].
HttpAdapter.NextCallback
type NextCallback = () => Promise<void>;
Async function passed to interceptors. Call await next() to continue to the next interceptor or the operation handler.
HttpAdapter.Events
Events are grouped into three sets: adapter-level, per-context lifecycle, and per-bundle lifecycle.
Adapter events
| Event | Payload | Emitted when |
|---|---|---|
'create-context' | ctx: HttpContext | A new HttpContext has been created, before interceptors run. |
'request' | ctx: HttpContext | The request enters the interceptor chain. |
'error' | error: Error, ctx?: HttpContext | An unhandled error occurred during request processing. |
Per-context lifecycle events (fired for every request, including sub-requests inside a bundle)
| Event | Payload | Emitted when |
|---|---|---|
'context-before-execute' | ctx: HttpContext | Immediately before the operation handler is called. |
'context-after-execute' | responseValue: any, ctx: HttpContext | After the operation handler returns successfully. |
'context-finish' | ctx: HttpContext | Context lifecycle complete. Always fires. |
Per-bundle lifecycle events (fired only for multipart/mixed batch requests)
| Event | Payload | Emitted when |
|---|---|---|
'bundle-before-execute' | bundle: HttpBundle | Before the first sub-request in the batch starts. |
'bundle-after-execute' | bundle: HttpBundle | After all sub-requests complete successfully. |
'bundle-finish' | bundle: HttpBundle | Bundle lifecycle complete. Always fires. |
// Adapter-level tracing across all requests
adapter.on('context-before-execute', ctx => {
ctx['_traceStart'] = Date.now();
});
adapter.on('context-finish', ctx => {
const ms = Date.now() - ctx['_traceStart'];
console.log(`${ctx.request.method} ${ctx.request.url} — ${ms}ms`);
});
// Bundle-level transaction logging
adapter.on('bundle-finish', bundle => {
const status = bundle.success ? 'committed' : 'rolled back';
console.log(`Batch ${status} (${bundle.size} requests)`);
});