Video

Watch the full video on YouTube:

Request and Response - @Req, @Res, @Headers and @Ip Decorators

Introduction

In this ninth installment of the NestJS guide, we’ll explore how to access request information and control the response in our controllers. NestJS provides a set of decorators that facilitate interaction with these objects, allowing us to obtain headers, cookies, IP addresses, and much more.

@Req Decorator - Accessing the Request

The @Req (or @Request) decorator allows us to access the complete request object, which contains all the information the client sends to our API.

Importing @Req

import { Req } from '@nestjs/common'
import { type Request } from 'express'

Using @Req in a Controller

@Post('example')
example(@Req() req: Request) {
  console.log(req.body)
  console.log(req.method)
  console.log(req.headers)
  console.log(req.query)
  console.log(req.params)
  return 1
}

Information Available in the Request

The request object contains:

  • body: The request body
  • method: The HTTP method used (GET, POST, PUT, etc.)
  • headers: The headers sent by the client
  • query: Query string parameters
  • params: Route parameters
  • cookies: Cookies sent by the client
  • IP: The client’s IP address

Example with Headers and Query

@Post('example')
example(@Req() req: Request) {
  console.log('Body:', req.body)
  console.log('Method:', req.method)
  console.log('Headers:', req.headers)
  console.log('Query:', req.query)
  return 1
}

Important: When using @Req, NestJS doesn’t automatically execute the validation pipeline. To validate data, it’s preferable to use specific decorators like @Body, @Query, or @Param.

@Ip Decorator - Getting the IP Address

The @Ip decorator allows us to directly obtain the client’s IP address making the request.

Importing @Ip

import { Ip } from '@nestjs/common'

Using @Ip

@Post('example')
example(@Ip() ip: string) {
  console.log('IP:', ip)
  return 1
}

The returned IP address is a mask representing the client’s approximate location.

@Headers Decorator - Accessing Headers

The @Headers decorator allows us to access the HTTP headers sent by the client.

Importing @Headers

import { Headers } from '@nestjs/common'

Get All Headers

@Post('example')
example(@Headers() headers: Record<string, string>) {
  console.log('Headers:', headers)
  return 1
}

Get a Specific Header

@Post('example')
example(@Headers('host') host?: string) {
  console.log('Host:', host)
  return 1
}

When we pass a header name, the decorator returns string | undefined since the header might not be present. If we don’t pass a name, it returns an object with all headers.

@Res Decorator and the Response Object

The @Res (or @Response) decorator gives us access to Express’s response object, allowing us to fully control the response we send to the client.

Importing @Res

import { Res } from '@nestjs/common'
import { type Response } from 'express'

Using @Res to Send Headers

@Post('example')
example(@Res() res: Response) {
  res.setHeader('X-Custom-Header', 'my-value')
  return res.send(1)
}

Important: When using @Res() without arguments, you delegate response control to Express (or Fastify). This means NestJS will no longer process the response through its interceptors and pipelines. You must handle sending the response manually using Express methods like res.send(), res.json(), etc.

Setting Status Code

@Post('example')
example(@Res() res: Response) {
  res.status(500)
  return res.send('Internal error')
}

passthrough - Delegating the Response to NestJS

When we use @Res, we delegate response control to Express. If we want NestJS to continue managing the lifecycle, we can use the passthrough option:

@Post('example')
example(@Res({ passthrough: true }) res: Response) {
  res.setHeader('X-Custom-Header', 'my-value')
  return 1  // NestJS will process the response
}

With passthrough: true, we can set headers and status codes while NestJS handles sending the final response through its interceptors and pipelines.

@Header Decorator - Static Headers

The @Header decorator allows us to set response headers statically in the method decorator:

@Post('example')
@Header('X-Custom-Header-2', 'milo')
example() {
  return 1
}

This approach is useful for headers that don’t depend on business logic.

@HttpCode Decorator - Custom Status Codes

The @HttpCode decorator allows us to set the HTTP status code that will be sent in the response:

import { HttpCode } from '@nestjs/common'

@Post('example')
@HttpCode(400)
example() {
  return 1
}

We can also use the HttpStatus enum from @nestjs/common:

import { HttpCode, HttpStatus } from '@nestjs/common'

@Post('example')
@HttpCode(HttpStatus.BAD_REQUEST)
example() {
  return 1
}

Decorators Summary

Decorator Function Example
@Req Access complete request @Req() req: Request
@Res Access complete response @Res() res: Response
@Ip Get client’s IP @Ip() ip: string
@Headers Access HTTP headers @Headers() headers: Record<string, string>
@Header Set static header @Header('key', 'value')
@HttpCode Set status code @HttpCode(200)

Best Practices

  1. Use specific decorators (@Body, @Query, @Param) instead of @Req for automatic validation
  2. Prefer @Res({ passthrough: true }) when you need to set headers but want NestJS to handle the response
  3. Don’t mix @Res with return without passthrough, as Express will take control and NestJS won’t process the response
  4. Use @HttpCode for endpoints that need non-standard status codes
  5. Extract business logic from controllers to services or handlers

Conclusion

Request and response decorators in NestJS give us full control over client interaction. From obtaining basic information like IP and headers, to fully controlling the response with custom status codes and headers. Proper use of these decorators is fundamental for creating robust and well-structured APIs.

Repository

💻 Repository: https://github.com/radagva/guia-de-nestjs-example

TypeScript Guide EP12: Creating Custom Utility TypesNestJS Guide EP10: Dependency Injection and Providers