Route parameters, query and body
A request carries data in three places: in the address itself (/posts/5), in the query string after the question mark (/posts?page=2) and in the body — for example, JSON with a new post. NestJS has a parameter decorator for each place: you put it in front of a method argument, and the framework fills in the value.
A route parameter
A part of the address with a colon is a parameter. The @Param() decorator reads it by name:
// src/posts/posts.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
@Controller('posts')
export class PostsController {
@Get(':id')
findOne(@Param('id') id: string) {
return `Post number ${id}`;
}
}Open http://localhost:3000/posts/5 — you will see "Post number 5". The value always arrives as a string, even if the address contains digits. The lesson about pipes shows how to turn it into a number.
There can be several parameters:
// src/posts/posts.controller.ts
@Get(':postId/comments/:commentId')
findComment(
@Param('postId') postId: string,
@Param('commentId') commentId: string,
) {
return `Comment ${commentId} on post ${postId}`;
}The address /posts/5/comments/12 returns "Comment 12 on post 5".
The query string
Parameters after ? are read by @Query():
// src/posts/posts.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
@Controller('posts')
export class PostsController {
@Get()
findAll(@Query('page') page?: string, @Query('search') search?: string) {
return { page: page ?? '1', search: search ?? '' };
}
}The address /posts?page=2&search=nest returns {"page":"2","search":"nest"}. If a parameter is missing from the address, the argument is undefined, so it is marked optional.
The request body
Data from the body of POST and PATCH requests comes through @Body(). NestJS parses JSON itself — nothing needs to be connected:
// src/posts/posts.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
@Controller('posts')
export class PostsController {
@Post()
create(@Body() body: { title: string; content: string }) {
return { message: 'Post created', title: body.title };
}
}Send a request from the terminal:
curl -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-d '{"title":"Hello, Nest","content":"First post"}'The server answers {"message":"Post created","title":"Hello, Nest"}. If you pass a field name to @Body(), for example @Body('title'), you get only that field.
Summary
| Decorator | Where the data comes from | Example address |
|---|---|---|
@Param('id') | Part of the address | /posts/5 |
@Query('page') | Query string | /posts?page=2 |
@Body() | Request body | POST /posts with JSON |
@Headers('user-agent') | Header | any |
Common mistake
The client sends JSON but forgets the Content-Type: application/json header. Then Express does not parse the body, and body turns out to be undefined or an empty object. If @Body() is empty, check this header first — in curl, Postman or in fetch() on the frontend.