Headers
OPRA gives you full access to both request headers (read-only) and response headers (read/write) through ctx.request and ctx.response. You can also declare expected request headers on the operation so they appear in the API schema.
Reading request headers
ctx.request.header(name) / ctx.request.get(name)
header(name: string): string | string[] | undefined
get(name: string): string | string[] | undefined
The two methods are aliases for each other. Header names are case-insensitive.
const contentType = ctx.request.header('content-type');
const auth = ctx.request.get('authorization');
const forwarded = ctx.request.header('x-forwarded-for');
The Referrer / Referer spellings are treated as interchangeable.
set-cookie is the only header that returns string[] instead of string — it returns an array, one entry per value.
ctx.request.headers
The full headers object is available as a plain Record<string, string | string[]>:
const allHeaders = ctx.request.headers;
Declaring expected request headers
Use .Header() in the operation decorator chain to declare a header parameter. Declared headers appear in the API schema and can carry type and validation metadata.
@(HttpOperation.GET()
.Header('Authorization', { type: 'string', required: true })
.Header('Accept-Language', 'string')
.Response(200, { type: Customer }))
async get(ctx: HttpContext) {
const lang = ctx.request.header('accept-language') ?? 'en';
// ...
}
.Header() options:
| Option | Type | Description |
|---|---|---|
type | Type | string | OPRA type for the header value. |
required | boolean | Whether the header must be present. |
default | any | Default value when the header is absent. |
deprecated | boolean | string | Mark the header as deprecated. |
description | string | Human-readable description for the schema. |
The first argument can be a string or a RegExp to match multiple header names at once.
Setting response headers
ctx.response.setHeader(name, value)
setHeader(name: string, value: number | string | readonly string[]): this
Sets or replaces a header on the response. Returns this for chaining.
ctx.response.setHeader('X-Request-Id', requestId);
ctx.response.setHeader('Cache-Control', 'no-store');
You can also pass an object to set multiple headers at once:
ctx.response.setHeader({
'X-Request-Id': requestId,
'Cache-Control': 'no-store',
'X-Powered-By': 'OPRA',
});
ctx.response.appendHeader(name, value)
appendHeader(name: string, value: string | readonly string[]): this
Appends to an existing header rather than replacing it. Useful for multi-value headers:
ctx.response.appendHeader('Vary', 'Accept-Encoding');
ctx.response.appendHeader('Vary', 'Accept-Language');
// Result: Vary: Accept-Encoding, Accept-Language
ctx.response.getHeader(name)
getHeader(name: string): number | string | string[] | undefined
Returns the current value of a response header already set in this response:
const ct = ctx.response.getHeader('content-type');
Content-Type shorthand
ctx.response.contentType() is a convenience wrapper around setHeader('Content-Type', ...). It accepts MIME types, file extensions, and short aliases:
ctx.response.contentType('application/json'); // explicit MIME
ctx.response.contentType('json'); // alias → application/json; charset=utf-8
ctx.response.contentType('.html'); // extension → text/html; charset=utf-8
ctx.response.contentType('png'); // → image/png
The adapter automatically appends ; charset=utf-8 for text-based MIME types.
Complete example
import { HttpController, HttpOperation } from '@opra/common';
import { HttpContext } from '@opra/http';
@HttpController({ path: 'reports' })
export class ReportsController {
@(HttpOperation.GET({ path: ':id' })
.PathParam('id', { type: 'integer' })
.Header('Accept-Language', { type: 'string', required: false })
.Header('X-Tenant-Id', { type: 'string', required: true })
.Response(200, { contentType: 'application/pdf' }))
async download(ctx: HttpContext) {
const lang = ctx.request.header('accept-language') ?? 'en';
const tenantId = ctx.request.header('x-tenant-id')!;
const pdf = await this.service.generateReport(ctx.pathParams.id, { lang, tenantId });
ctx.response
.setHeader('Content-Disposition', `attachment; filename="report-${ctx.pathParams.id}.pdf"`)
.setHeader('X-Report-Version', '2');
return pdf; // Buffer → application/pdf
}
}