Skip to main content

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:

OptionTypeDescription
typeType | stringOPRA type for the header value.
requiredbooleanWhether the header must be present.
defaultanyDefault value when the header is absent.
deprecatedboolean | stringMark the header as deprecated.
descriptionstringHuman-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
}
}

Cookies · Reading the Request Body · Sending Responses