Skip to Content

@TypedHeaders

@nestia/core
export function TypedHeaders(): ParameterDecorator;

Drop-in replacement for @Headers() from @nestjs/common. Behavior is identical plus:

  • Each declared header is validated against the declared TypeScript type.
  • Header values are coerced — "42" → 42, "true" → true, repeated headers → string[].
  • A type mismatch returns 400 Bad Request.

For auth tokens (Authorization header) and other identity carries, the typical NestJS pattern is a custom @User() decorator backed by a guard — not @TypedHeaders. Use this decorator for application-defined headers that carry data your handler needs: tenant codes, language preferences, custom x-… headers.


Basic usage

src/controllers/ArticlesController.ts
import { TypedHeaders, TypedRoute } from "@nestia/core"; import { Controller } from "@nestjs/common"; interface IRequestHeaders { "x-tenant": string; "x-locale"?: "en" | "ko" | "ja"; "x-version": number; } @Controller("articles") export class ArticlesController { @TypedRoute.Get() public async list( @TypedHeaders() headers: IRequestHeaders, ): Promise<IArticle[]> { const tenant = headers["x-tenant"]; const locale = headers["x-locale"] ?? "en"; // ... } }

A request without x-tenant returns 400. A request with x-version: abc returns 400. A request with valid headers calls the handler with the typed object.


Header-name conventions

  • Lowercase preferred. HTTP header names are case-insensitive on the wire, but Node normalizes them to lowercase. Declare "x-tenant", not "X-Tenant".
  • Uppercase tolerated. If the interface declares "X-Foo", Nestia matches it case-insensitively against the request — the value lands at the casing you declared.
  • Repeated headers (e.g. multiple Accept lines) become string[] on the parameter. Declare the field as an array type.

What gets coerced

Declared typeWire exampleCoerces to
string"foo""foo"
number"42"42
boolean"true" / "false"true / false
"a" | "b""a""a" (validated)
string[]repeated header["v1","v2"]
number[]repeated header, or "1, 2, 3" as Node joins repeats[1, 2, 3]
Optional (?)header absentundefined

Tags layered on top (MinLength, Pattern, etc.) work the same as on body / query types.


When to use plain @Headers instead

Reach for the vanilla decorator when:

  • The header carries opaque data (Authorization: Bearer …) and you delegate parsing to a guard.
  • You need every header, not a known subset — read them from @Req(), which the SDK ignores; the SDK and Swagger cannot describe arbitrary header names.

@nestia/sdk reads the declared type of @TypedHeaders() and vanilla @Headers() parameters alike into the SDK and the Swagger document, and holds both to the same header rules: one object of statically named atomic properties, none nullable, arrays only where a header may repeat, and a field-named @Headers("key") of an atomic type or an array of them. A dynamic key such as Record<string, string> is reported as a diagnostic, because no document can list arbitrary headers and the SDK could not send them. The vanilla decorator only skips coercion and validation.


See also

Last updated on