diff --git a/content/controllers.md b/content/controllers.md index 0bc1cec08a..8ac6cc6add 100644 --- a/content/controllers.md +++ b/content/controllers.md @@ -102,7 +102,7 @@ export class CatsController { > info **Hint** To take advantage of `express` typings (like in the `request: Request` parameter example above), make sure to install the `@types/express` package. -The request object represents the HTTP request and contains properties for the query string, parameters, HTTP headers, and body (read more [here](https://expressjs.com/en/api.html#req)). In most cases, you don't need to manually access these properties. Instead, you can use dedicated decorators like `@Body()` or `@Query()`, which are available out of the box. Below is a list of the provided decorators and the corresponding platform-specific objects they represent. +The request object represents the HTTP request and contains properties for the query string, parameters, HTTP headers, and body (read more [here](https://expressjs.com/en/api.html#req)). In most cases, you don't need to manually access these properties. Instead, you can use dedicated decorators like `@Body()` or `@QueryString()`, which are available out of the box. Below is a list of the provided **parameter** decorators and the corresponding platform-specific objects they represent. @@ -130,7 +130,7 @@ The request object represents the HTTP request and contains properties for the q - + @@ -189,7 +189,18 @@ export class CatsController { } ``` -It's that simple. Nest provides decorators for all of the standard HTTP methods: `@Get()`, `@Post()`, `@Put()`, `@Delete()`, `@Patch()`, `@Options()`, and `@Head()`. In addition, `@All()` defines an endpoint that handles all of them. +It's that simple. Nest provides decorators for all of the standard HTTP methods: `@Get()`, `@Post()`, `@Put()`, `@Delete()`, `@Patch()`, `@Options()`, and `@Head()`. Nest also provides `@Query()` and `@Search()` for the corresponding HTTP methods. In addition, `@All()` defines an endpoint that handles all of them. + +```typescript +@Query('search') +find(@Body() filters: SearchDto) { + return this.service.search(filters); +} +``` + +> info **Hint** The HTTP `QUERY` method is safe and idempotent and carries a request body; use `@Body()` for the payload (not `@QueryString()`). Runtime support depends on Node.js including `QUERY` in `http.METHODS` (typically `>=20.19.3 <21` or `>=22.2.0`). Express 5 (the default via `@nestjs/platform-express`) exposes `app.query` when Node includes `QUERY`; the Fastify adapter registers the verb via `query(...)`. Client and proxy support may vary. + +> warning **Warning** Do not confuse the `@Query()` **method** decorator (HTTP `QUERY` routes) with `@QueryString()`, the **parameter** decorator that extracts URL query string values from `req.query`. #### Route wildcards @@ -256,7 +267,7 @@ Returned values will override any arguments passed to the `@Redirect()` decorato ```typescript @Get('docs') @Redirect('https://docs.nestjs.com', 302) -getDocs(@Query('version') version) { +getDocs(@QueryString('version') version) { if (version && version === '5') { return { url: 'https://docs.nestjs.com/v5/' }; } @@ -408,19 +419,21 @@ async create(createCatDto) { #### Query parameters -When handling query parameters in your routes, you can use the `@Query()` decorator to extract them from incoming requests. Let's see how this works in practice. +When handling query parameters in your routes, you can use the `@QueryString()` decorator to extract them from incoming requests. Let's see how this works in practice. + +> warning **Warning** Previously this was `@Query()`. That name is now reserved for the HTTP `QUERY` **method** decorator. Use `@QueryString()` to read `req.query`. Consider a route where we want to filter a list of cats based on query parameters like `age` and `breed`. First, define the query parameters in the `CatsController`: ```typescript @@filename(cats.controller) @Get() -async findAll(@Query('age') age: number, @Query('breed') breed: string) { +async findAll(@QueryString('age') age: number, @QueryString('breed') breed: string) { return `This action returns all cats filtered by age: ${age} and breed: ${breed}`; } ``` -In this example, the `@Query()` decorator is used to extract the values of `age` and `breed` from the query string. For example, a request to: +In this example, the `@QueryString()` decorator is used to extract the values of `age` and `breed` from the query string. For example, a request to: ```plaintext GET /cats?age=2&breed=Persian @@ -465,7 +478,7 @@ Below is an example that demonstrates the use of several available decorators to ```typescript @@filename(cats.controller) -import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common'; +import { Controller, Get, QueryString, Post, Body, Put, Param, Delete } from '@nestjs/common'; import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto'; @Controller('cats') @@ -476,7 +489,7 @@ export class CatsController { } @Get() - findAll(@Query() query: ListAllEntities) { + findAll(@QueryString() query: ListAllEntities) { return `This action returns all cats (limit: ${query.limit} items)`; } @@ -496,7 +509,7 @@ export class CatsController { } } @@switch -import { Controller, Get, Query, Post, Body, Put, Param, Delete, Bind } from '@nestjs/common'; +import { Controller, Get, QueryString, Post, Body, Put, Param, Delete, Bind } from '@nestjs/common'; @Controller('cats') export class CatsController { @@ -507,7 +520,7 @@ export class CatsController { } @Get() - @Bind(Query()) + @Bind(QueryString()) findAll(query) { console.log(query); return `This action returns all cats (limit: ${query.limit} items)`; diff --git a/content/custom-decorators.md b/content/custom-decorators.md index 31bec3fdf5..4ae034b6ad 100644 --- a/content/custom-decorators.md +++ b/content/custom-decorators.md @@ -39,7 +39,7 @@ Nest provides a set of useful **param decorators** that you can use together wit - + @@ -156,7 +156,7 @@ You can use this same decorator with different keys to access different properti #### Working with pipes -Nest treats custom param decorators in the same fashion as the built-in ones (`@Body()`, `@Param()` and `@Query()`). This means that pipes are executed for the custom annotated parameters as well (in our examples, the `user` argument). Moreover, you can apply the pipe directly to the custom decorator: +Nest treats custom param decorators in the same fashion as the built-in ones (`@Body()`, `@Param()` and `@QueryString()`). This means that pipes are executed for the custom annotated parameters as well (in our examples, the `user` argument). Moreover, you can apply the pipe directly to the custom decorator: ```typescript @@filename() diff --git a/content/faq/request-lifecycle.md b/content/faq/request-lifecycle.md index 3e80edeff0..5bfa661e9b 100644 --- a/content/faq/request-lifecycle.md +++ b/content/faq/request-lifecycle.md @@ -47,7 +47,7 @@ export class CatsController { updateCat( @Body() body: UpdateCatDTO, @Param() params: UpdateCatParams, - @Query() query: UpdateCatQuery, + @QueryString() query: UpdateCatQuery, ) { return this.catsService.updateCat(body, params, query); } diff --git a/content/migration.md b/content/migration.md index 2930a62354..57dab4729b 100644 --- a/content/migration.md +++ b/content/migration.md @@ -352,3 +352,28 @@ $ mau deploy ``` You can learn more about Mau [in this chapter](/deployment#easy-deployment-with-mau). + +#### `@Query()` and `@QueryString()` + +> warning **BREAKING CHANGE** (NestJS release that introduces HTTP `QUERY` support; see [nestjs/nest#17397](https://github.com/nestjs/nest/pull/17397)) +> +> - Rename: `@Query()` parameter decorator → `@QueryString()` +> - New: `@Query()` method decorator routes HTTP `QUERY` requests + +The former `@Query()` **parameter** decorator (which extracted URL query string values from `req.query`) has been renamed to `@QueryString()`. The `@Query()` name is now the **method** decorator for the HTTP `QUERY` verb (same pattern as `@Get()`, `@Post()`, `@Search()`, and so on). Handlers for HTTP `QUERY` should read the payload with `@Body()`. + +```typescript +// before +@Get() +find(@Query('page') page: string) {} + +// after +@Get() +find(@QueryString('page') page: string) {} + +// new HTTP QUERY route +@Query('items') +search(@Body() body: FiltersDto) {} +``` + +> info **Hint** Runtime support for the HTTP `QUERY` method depends on Node.js including `QUERY` in `http.METHODS` (typically `>=20.19.3 <21` or `>=22.2.0`). See [Controllers](/controllers#resources) for more details. diff --git a/content/openapi/types-and-parameters.md b/content/openapi/types-and-parameters.md index 5c881e003b..1f443f5aef 100644 --- a/content/openapi/types-and-parameters.md +++ b/content/openapi/types-and-parameters.md @@ -1,6 +1,6 @@ ### Types and parameters -The `SwaggerModule` searches for all `@Body()`, `@Query()`, and `@Param()` decorators in route handlers to generate the API document. It also creates corresponding model definitions by taking advantage of reflection. Consider the following code: +The `SwaggerModule` searches for all `@Body()`, `@QueryString()`, and `@Param()` decorators in route handlers to generate the API document. It also creates corresponding model definitions by taking advantage of reflection. Consider the following code: ```typescript @Post() @@ -120,11 +120,11 @@ export enum UserRole { } ``` -You can then use the enum directly with the `@Query()` parameter decorator in combination with the `@ApiQuery()` decorator. +You can then use the enum directly with the `@QueryString()` parameter decorator in combination with the `@ApiQuery()` decorator. ```typescript @ApiQuery({ name: 'role', enum: UserRole }) -async filterByRole(@Query('role') role: UserRole = UserRole.User) {} +async filterByRole(@QueryString('role') role: UserRole = UserRole.User) {} ```
diff --git a/content/pipes.md b/content/pipes.md index fc6a9094cf..a6097f5ced 100644 --- a/content/pipes.md +++ b/content/pipes.md @@ -85,7 +85,7 @@ For example with a query string parameter: ```typescript @Get() -async findOne(@Query('id', ParseIntPipe) id: number) { +async findOne(@QueryString('id', ParseIntPipe) id: number) { return this.catsService.findOne(id); } ``` @@ -165,7 +165,7 @@ These properties describe the currently processed argument. @@ -549,14 +549,14 @@ We leave the implementation of this pipe to the reader, but note that like all o #### Providing defaults -`Parse*` pipes expect a parameter's value to be defined. They throw an exception upon receiving `null` or `undefined` values. To allow an endpoint to handle missing querystring parameter values, we have to provide a default value to be injected before the `Parse*` pipes operate on these values. The `DefaultValuePipe` serves that purpose. Simply instantiate a `DefaultValuePipe` in the `@Query()` decorator before the relevant `Parse*` pipe, as shown below: +`Parse*` pipes expect a parameter's value to be defined. They throw an exception upon receiving `null` or `undefined` values. To allow an endpoint to handle missing querystring parameter values, we have to provide a default value to be injected before the `Parse*` pipes operate on these values. The `DefaultValuePipe` serves that purpose. Simply instantiate a `DefaultValuePipe` in the `@QueryString()` decorator before the relevant `Parse*` pipe, as shown below: ```typescript @@filename() @Get() async findAll( - @Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean, - @Query('page', new DefaultValuePipe(0), ParseIntPipe) page: number, + @QueryString('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean, + @QueryString('page', new DefaultValuePipe(0), ParseIntPipe) page: number, ) { return this.catsService.findAll({ activeOnly, page }); } diff --git a/content/techniques/serialization.md b/content/techniques/serialization.md index f225a1dbaa..6830458090 100644 --- a/content/techniques/serialization.md +++ b/content/techniques/serialization.md @@ -108,7 +108,7 @@ In the example below, despite returning plain JavaScript objects in both conditi @UseInterceptors(ClassSerializerInterceptor) @SerializeOptions({ type: UserEntity }) @Get() -findOne(@Query() { id }: { id: number }): UserEntity { +findOne(@QueryString() { id }: { id: number }): UserEntity { if (id === 1) { return { id: 1, diff --git a/content/techniques/validation.md b/content/techniques/validation.md index ab9d28cdab..bfe1c02556 100644 --- a/content/techniques/validation.md +++ b/content/techniques/validation.md @@ -286,7 +286,7 @@ Alternatively (with auto-transformation disabled), you can explicitly cast value @Get(':id') findOne( @Param('id', ParseIntPipe) id: number, - @Query('sort', ParseBoolPipe) sort: boolean, + @QueryString('sort', ParseBoolPipe) sort: boolean, ) { console.log(typeof id === 'number'); // true console.log(typeof sort === 'boolean'); // true @@ -420,7 +420,7 @@ In addition, the `ParseArrayPipe` may come in handy when parsing query parameter ```typescript @Get() findByIds( - @Query('ids', new ParseArrayPipe({ items: Number, separator: ',' })) + @QueryString('ids', new ParseArrayPipe({ items: Number, separator: ',' })) ids: number[], ) { return 'This action returns users by ids';
req.body / req.body[key]
@Query(key?: string)@QueryString(key?: string) req.query / req.query[key]
req.body / req.body[param]
@Query(param?: string)@QueryString(param?: string) req.query / req.query[param]
Indicates whether the argument is a body @Body(), query - @Query(), param + @QueryString(), param @Param(), or a custom parameter (read more here).