How to Extract and Parse Headers in NestJS

Updated: December 31, 2023 By: Guest Contributor Post a comment

Introduction

In NestJS, a powerful server-side JavaScript framework built with TypeScript, handling request headers is crucial for many web applications. This guide will discuss how to effectively extract and parse request headers in NestJS, enabling fine-grained request inspection and manipulation.

Basic Header Extraction

To start off, let’s discuss the basics of how to extract headers from incoming HTTP requests in NestJS. Typically, you use decorators to achieve this.

First, ensure your NestJS environment is set up. If you need to install NestJS, you can do so using the following command:

npm i -g @nestjs/cli
nestjs new my-project
cd my-project
npm run start

Next, in your controller, import Headers from @nestjs/common package and use it as a decorator for your route handler’s argument:

import { Controller, Get, Headers } from '@nestjs/common';

@Controller('demo')
export class DemoController {
  @Get()
  getHeaders(@Headers() headers: any) {
    console.log(headers);
    return headers;
  }
}

The @Headers() decorator provides the headers object, which contains all the request headers.

Parsing Specific Headers

If you’re interested in a specific header, you can supply its name as a parameter to the @Headers() decorator:

import { Controller, Get, Headers } from '@nestjs/common';

@Controller('demo')
export class DemoController {
  @Get('special')
  getSpecificHeader(@Headers('authorization') authHeader: string) {
    console.log(authHeader);
    return authHeader;
  }
}

This code will extract the Authorization header and make it available in your handler method.

Using DTOs to Parse Headers

For a more structured approach, especially when dealing with multiple headers or when you want to enforce specific types, you can use DTOs (Data Transfer Objects).

import { Controller, Get, Headers } from '@nestjs/common';

class HeaderDto {
  'user-agent': string;
  authorization?: string;
}

@Controller('demo')
export class DemoController {
  @Get('dto')
  getDtoHeaders(@Headers() headers: HeaderDto) {
    console.log(headers);
    return headers;
  }
}

In the above example, we have a DTO that expects the User-Agent and optionally the Authorization header. NestJS will automatically attempt to match and assign the incoming headers to this DTO object.

Advanced Header Parsing with Pipes

For advanced scenarios, you may want to transform or validate headers. NestJS provides pipes for these tasks. Below is an example of how you might create a pipe to validate an API key passed in a header:

import { Injectable, PipeTransform, BadRequestException } from '@nestjs/common';

@Injectable()
export class ApiKeyPipe implements PipeTransform {
  transform(value: any): string {
    if (!value.authorization) {
      throw new BadRequestException('API key not provided');
    }

    if (value.authorization !== 'expected-api-key') {
      throw new BadRequestException('Invalid API key');
    }
    return value.authorization;
  }
}

Apply your pipe in your controller:

import { UsePipes } from '@nestjs/common';

@Controller('secure')
export class SecureController {
  @Get()
  @UsePipes(new ApiKeyPipe())
  secureEndpoint(@Headers() headers: any) {
    return 'Access granted';
  }
}

With @UsePipes(), the ApiKeyPipe will validate every request to the secured endpoint.

Extracting Header Arrays

HTTP allows multiple values for the same header under certain conditions. You can extract such values in NestJS by just looking for them in the headers object:

import { Controller, Get, Headers } from '@nestjs/common';

@Controller('array')
export class ArrayHeaderController {
  @Get()
  getArrayHeaders(@Headers('set-cookie') cookies: string[] | string) {
    console.log(Array.isArray(cookies) ? cookies : [cookies]);
    return cookies;
  }
}

In cases when multiple headers are present, the value is an array, otherwise it’s a single string.

Typing and Interfaces

To further enforce clean code and type safety, you can use TypeScript interfaces:

import { Controller, Get, Headers } from '@nestjs/common';

interface MyHeaders {
  authorization?: string;
  'user-agent': string;
}

@Controller('typed')
export class TypedController {
  @Get()
  getTypedHeaders(@Headers() headers: MyHeaders) {
    console.log(headers);
    return headers;
  }
}

Applying interfaces can help to prevent accessing undefined headers and improve overall code reliability.

Conclusion

The process of extracting and parsing headers in NestJS is straightforward but powerful. By using decorators, DTOs, pipes, and interfaces, you can effortlessly manage request headers and inject only what your application needs. Mastering these capabilities allows you to write more secure, efficient, and maintainable NestJS applications.