đź“– Guide Documents
Core Library
TypedHeaders

Outline

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

Request headers decorator, type safe.

@TypedHeaders() is a decorator function parsing request headers to a typed object. It validates the request header values through typia.assert<T>() (opens in a new tab). If the request header values are invalid, it will throw 400 bad request exception.

It is almost same with original @Headers() of NestJS, but much type safe.

⚠️

@TypedHeaders() is not essential for Swagger Documents or SDK Library building.

Therefore, it is not a matter to use @TypedHeaders() or @Headers() of the original NestJS.

How to use

HeadersController.ts
import { Controller } from "@nestjs/common";
 
import core from "@nestia/core";
 
import { IHeaders } from "@api/lib/structures/IHeaders";
 
@Controller("headers/:section")
export class HeadersController {
  /**
   * Emplace headers.
   *
   * @param headers Headers for authentication
   * @param section Target section code
   * @returns Store article
   *
   * @author Samchon
   */
  @core.TypedRoute.Patch()
  public emplace(
    @core.TypedHeaders() headers: IHeaders,
    @core.TypedParam("section", "string") section: string,
  ): void {
    headers;
    section;
  }
}

Just call @TypedHeaders() function on the request headers parameter, that's all.

Nestia will analyze your type (IHeaders), and write optimal conversion and validation code for the target type, in the compilation level. If you click the "Compiled JavaScript File" tab of above, you can see the optimal code.

Also, as you can see from the "Compiled JavaScript File", when upper case alphabet is used in the header key name like IHeaders["X-Descriptions"], @TypedHeaders() would automatically convert to the upper case alphabet key named property from lower case key named property of raw data.

Such optimization is called AOT (Ahead of Time) compilation, and it is the secret of @TypedHeaders

Besides, the original @Headers() decorator of NestJS does not support such automatic upper case conversion. When you've define upper-cased property name in DTO, undefined value always be assigned, even if you've sent upper-cased property in the client side.

Special Tags

You can enhance validation logic, of @TypedHeaders(), through comment tags.

You know what? @TypedHeaders() utilizes typia.assert<T>() (opens in a new tab) function for query data validation, and the typia.assert<T>() (opens in a new tab) function supports additional type checking logics through comment tags. For reference, "Type Tag" means a intersection type with atomic type and special tag type of typia like number & tags.Type<"uint32">, and "Comment Tag" means a comment starting from @ symbol following @${name} ${value} format.

With those type and comment tags, you can add additional validation logics. If you want to add a custom validation logic, you also can do it. Read below Guide Docments of typia (opens in a new tab), and see the example code. You may understand how to utilize such type and comment tags, in a few minutes.

examples/src/is-special-tags.ts
import typia, { tags } from "typia";
 
export const checkSpecialTag = typia.createIs<SpecialTag>();
 
interface SpecialTag {
  int32: number & tags.Type<"int32">;
  range?: number & tags.ExclusiveMinimum<19> & tags.Maximum<100>;
  minLength: string & tags.MinLength<3>;
  pattern: string & tags.Pattern<"^[a-z]+$">;
  date: null | (string & tags.Format<"date">);
  ip: string & (tags.Format<"ipv4"> | tags.Format<"ipv6">);
  uuids: Array<string & tags.Format<"uuid">> &
    tags.MinItems<3> &
    tags.MaxItems<100>;
}

Restriction

When using @TypedHeaders(), you've to follow such restrictions.

At first, type of @TypedHeaders() must be a pure object type. It does not allow union type. Also, nullable types are not allowed, either. Note that, request headers type must be a sole object type without any extra definition. Of course, the word object does not contain array type.

At next, type of properties must be atomic, or array of atomic type. In the atomic type case, the atomic type allows both nullable and undefindable types. However, mixed union atomic type like string | number or "1" | "2" | 3 are not allowed. Also, the array type does not allow both nullable and undefindable types, either.

  • boolean
  • number
  • bigint
  • string

At last, HTTP headers has special restriction on value types for specific key names. For example, Set-Cookie must be Array type, and Authorization must be an atomic type like string. Therefore, @TypedHeaders() also restricts the value type of specific key names, and it is described in below.

  • Only array type allowed:
    • set-cookie
  • Only atomic type allowed:
    • age
    • authorization
    • content-length
    • content-type
    • etag
    • expires
    • from
    • host
    • if-modified-since
    • if-unmodified-since
    • last-modified
    • location
    • max-forwards
    • proxy-authorization
    • referer
    • retry-after
    • server
    • user-agent
SomeHeadersDto.ts
export interface SomeHeadersDto {
  //----
  // ATOMIC TYPES
  //----
  // ALLOWED
  boolean: boolean;
  number: number;
  string: string;
  bigint: bigint;
  optional_number?: number;
  nullable_string: string | null;
  literal_union: "A" | "B" | "C" | "D";
 
  // NOT ALLOWED
  mixed_union: string | number | boolean;
  mixed_literal: "A" | "B" | 3;
 
  //----
  // ARRAY TYPES
  //----
  // ALLOWED
  nullable_element_array: (string | null)[];
  string_array: string[];
  number_array: number[];
  literal_union_array: ("A" | "B" | "C")[];
  literal_tuple: ["A", "B", "C"];
 
  // NOT ALLOWED
  optional_element_array: (string | undefined)[];
  optional_array: string[] | undefined;
  nullable_array: string[] | null;
  union_atomic_array: (string | number)[];
  mixed_literal_array: ("A", "B", 3)[];
  mixed_tuple: ["A", "B", 3];
 
  //----
  // SPECIAL CASES
  //----
  // MUST BE ARRAY
  "Set-Cookie": string[];
 
  // MUST BE ATOMIC
  Accept: string;
  Authorization: string;
 
  // NOT ALLOWED - MUST BE ATOMIC
  referer: string[];
  age: number[];
}