mirror of
https://github.com/nestjs/docs.nestjs.com.git
synced 2026-02-25 22:15:07 +00:00
docs: improve wording in components, controllers, and modules
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
### Providers
|
||||
|
||||
Providers are a fundamental concept in Nest. Many of the basic Nest classes may be treated as a provider – services, repositories, factories, helpers, and so on. The main idea of a provider is that it can be **injected** as a dependency; this means objects can create various relationships with each other, and the function of "wiring up" these objects can largely be delegated to the Nest runtime system.
|
||||
Providers are a core concept in Nest. Many of the basic Nest classes, such as services, repositories, factories, and helpers, can be treated as providers. The key idea behind a provider is that it can be **injected** as a dependency, allowing objects to form various relationships with each other. The responsibility of "wiring up" these objects is largely handled by the Nest runtime system.
|
||||
|
||||
<figure><img class="illustrative-image" src="/assets/Components_1.png" /></figure>
|
||||
|
||||
In the previous chapter, we built a simple `CatsController`. Controllers should handle HTTP requests and delegate more complex tasks to **providers**. Providers are plain JavaScript classes that are declared as `providers` in a NestJS module. For more information, see the "Modules" chapter.
|
||||
In the previous chapter, we created a simple `CatsController`. Controllers should handle HTTP requests and delegate more complex tasks to **providers**. Providers are plain JavaScript classes declared as `providers` in a NestJS module. For more details, refer to the "Modules" chapter.
|
||||
|
||||
> info **Hint** Since Nest enables the possibility to design and organize dependencies in a more OO way, we strongly recommend following the [SOLID principles](https://en.wikipedia.org/wiki/SOLID).
|
||||
> info **Hint** Since Nest enables you to design and organize dependencies in an object-oriented manner, we strongly recommend following the [SOLID principles](https://en.wikipedia.org/wiki/SOLID).
|
||||
|
||||
#### Services
|
||||
|
||||
Let's start by creating a simple `CatsService`. This service will be responsible for data storage and retrieval, and is designed to be used by the `CatsController`, so it's a good candidate to be defined as a provider.
|
||||
Let's begin by creating a simple `CatsService`. This service will handle data storage and retrieval, and it will be used by the `CatsController`. Because of its role in managing the application's logic, it’s an ideal candidate to be defined as a provider.
|
||||
|
||||
```typescript
|
||||
@@filename(cats.service)
|
||||
@@ -50,7 +50,9 @@ export class CatsService {
|
||||
|
||||
> info **Hint** To create a service using the CLI, simply execute the `$ nest g service cats` command.
|
||||
|
||||
Our `CatsService` is a basic class with one property and two methods. The only new feature is that it uses the `@Injectable()` decorator. The `@Injectable()` decorator attaches metadata, which declares that `CatsService` is a class that can be managed by the Nest [IoC](https://en.wikipedia.org/wiki/Inversion_of_control) container. By the way, this example also uses a `Cat` interface, which probably looks something like this:
|
||||
Our `CatsService` is a basic class with one property and two methods. The key addition here is the `@Injectable()` decorator. This decorator attaches metadata to the class, signaling that `CatsService` is a class that can be managed by the Nest [IoC](https://en.wikipedia.org/wiki/Inversion_of_control) container.
|
||||
|
||||
Additionally, this example makes use of a `Cat` interface, which likely looks something like this:
|
||||
|
||||
```typescript
|
||||
@@filename(interfaces/cat.interface)
|
||||
@@ -108,13 +110,13 @@ export class CatsController {
|
||||
}
|
||||
```
|
||||
|
||||
The `CatsService` is **injected** through the class constructor. Notice the use of the `private` syntax. This shorthand allows us to both declare and initialize the `catsService` member immediately in the same location.
|
||||
The `CatsService` is **injected** through the class constructor. Notice the use of the `private` keyword. This shorthand allows us to both declare and initialize the `catsService` member in the same line, streamlining the process.
|
||||
|
||||
#### Dependency injection
|
||||
|
||||
Nest is built around the strong design pattern commonly known as **Dependency injection**. We recommend reading a great article about this concept in the official [Angular documentation](https://angular.dev/guide/di).
|
||||
Nest is built around the powerful design pattern known as **Dependency Injection**. We highly recommend reading a great article about this concept in the official [Angular documentation](https://angular.dev/guide/di).
|
||||
|
||||
In Nest, thanks to TypeScript capabilities, it's extremely easy to manage dependencies because they are resolved just by type. In the example below, Nest will resolve the `catsService` by creating and returning an instance of `CatsService` (or, in the normal case of a singleton, returning the existing instance if it has already been requested elsewhere). This dependency is resolved and passed to your controller's constructor (or assigned to the indicated property):
|
||||
In Nest, thanks to TypeScript's capabilities, managing dependencies is straightforward because they are resolved based on their type. In the example below, Nest will resolve the `catsService` by creating and returning an instance of `CatsService` (or, in the case of a singleton, returning the existing instance if it has already been requested elsewhere). This dependency is then injected into your controller's constructor (or assigned to the specified property):
|
||||
|
||||
```typescript
|
||||
constructor(private catsService: CatsService) {}
|
||||
@@ -122,19 +124,19 @@ constructor(private catsService: CatsService) {}
|
||||
|
||||
#### Scopes
|
||||
|
||||
Providers normally have a lifetime ("scope") synchronized with the application lifecycle. When the application is bootstrapped, every dependency must be resolved, and therefore every provider has to be instantiated. Similarly, when the application shuts down, each provider will be destroyed. However, there are ways to make your provider lifetime **request-scoped** as well. You can read more about these techniques in the [Injection Scopes](/fundamentals/injection-scopes) chapter.
|
||||
Providers typically have a lifetime ("scope") that aligns with the application lifecycle. When the application is bootstrapped, each dependency must be resolved, meaning every provider gets instantiated. Similarly, when the application shuts down, all providers are destroyed. However, it’s also possible to make a provider **request-scoped**, meaning its lifetime is tied to a specific request rather than the application's lifecycle. You can learn more about these techniques in the [Injection Scopes](/fundamentals/injection-scopes) chapter.
|
||||
|
||||
<app-banner-courses></app-banner-courses>
|
||||
|
||||
#### Custom providers
|
||||
|
||||
Nest has a built-in inversion of control ("IoC") container that resolves relationships between providers. This feature underlies the dependency injection feature described above, but is in fact far more powerful than what we've described so far. There are several ways to define a provider: you can use plain values, classes, and either asynchronous or synchronous factories. More examples of defining providers can be found in the [Dependency Injection](/fundamentals/dependency-injection) chapter.
|
||||
Nest comes with a built-in inversion of control ("IoC") container that manages the relationships between providers. This feature is the foundation of dependency injection, but it’s actually much more powerful than we've covered so far. There are several ways to define a provider: you can use plain values, classes, and both asynchronous or synchronous factories. For more examples of defining providers, check out the [Dependency Injection](/fundamentals/dependency-injection) chapter.
|
||||
|
||||
#### Optional providers
|
||||
|
||||
Occasionally, you might have dependencies which do not necessarily have to be resolved. For instance, your class may depend on a **configuration object**, but if none is passed, the default values should be used. In such a case, the dependency becomes optional, because lack of the configuration provider wouldn't lead to errors.
|
||||
Occasionally, you may have dependencies that don't always need to be resolved. For example, your class might depend on a **configuration object**, but if none is provided, default values should be used. In such cases, the dependency is considered optional, and the absence of the configuration provider should not result in an error.
|
||||
|
||||
To indicate a provider is optional, use the `@Optional()` decorator in the constructor's signature.
|
||||
To mark a provider as optional, use the `@Optional()` decorator in the constructor's signature.
|
||||
|
||||
```typescript
|
||||
import { Injectable, Optional, Inject } from '@nestjs/common';
|
||||
@@ -145,11 +147,11 @@ export class HttpService<T> {
|
||||
}
|
||||
```
|
||||
|
||||
Note that in the example above we are using a custom provider, which is the reason we include the `HTTP_OPTIONS` custom **token**. Previous examples showed constructor-based injection indicating a dependency through a class in the constructor. You can read more about custom providers and their associated tokens in the [Custom Providers](/fundamentals/custom-providers) chapter.
|
||||
In the example above, we're using a custom provider, which is why we include the `HTTP_OPTIONS` custom **token**. Previous examples demonstrated constructor-based injection, where a dependency is indicated through a class in the constructor. For more details on custom providers and how their associated tokens work, check out the [Custom Providers](/fundamentals/custom-providers) chapter.
|
||||
|
||||
#### Property-based injection
|
||||
|
||||
The technique we've used so far is called constructor-based injection, as providers are injected via the constructor method. In some very specific cases, **property-based injection** might be useful. For instance, if your top-level class depends on either one or multiple providers, passing them all the way up by calling `super()` in sub-classes from the constructor can be very tedious. In order to avoid this, you can use the `@Inject()` decorator at the property level.
|
||||
The technique we've used so far is called constructor-based injection, where providers are injected through the constructor method. In certain specific cases, **property-based injection** can be useful. For example, if your top-level class depends on one or more providers, passing them all the way up through `super()` in sub-classes can become cumbersome. To avoid this, you can use the `@Inject()` decorator directly at the property level.
|
||||
|
||||
```typescript
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
@@ -161,11 +163,11 @@ export class HttpService<T> {
|
||||
}
|
||||
```
|
||||
|
||||
> warning **Warning** If your class doesn't extend another class, you should always prefer using **constructor-based** injection. The constructor explicitly outlines what dependencies are required and provides better visibility than class attributes annotated with `@Inject`.
|
||||
> warning **Warning** If your class doesn't extend another class, it's generally better to use **constructor-based** injection. The constructor clearly specifies which dependencies are required, offering better visibility and making the code easier to understand compared to class properties annotated with `@Inject`.
|
||||
|
||||
#### Provider registration
|
||||
|
||||
Now that we have defined a provider (`CatsService`), and we have a consumer of that service (`CatsController`), we need to register the service with Nest so that it can perform the injection. We do this by editing our module file (`app.module.ts`) and adding the service to the `providers` array of the `@Module()` decorator.
|
||||
Now that we've defined a provider (`CatsService`) and a consumer (`CatsController`), we need to register the service with Nest so that it can handle the injection. This is done by editing the module file (`app.module.ts`) and adding the service to the `providers` array in the `@Module()` decorator.
|
||||
|
||||
```typescript
|
||||
@@filename(app.module)
|
||||
@@ -182,7 +184,7 @@ export class AppModule {}
|
||||
|
||||
Nest will now be able to resolve the dependencies of the `CatsController` class.
|
||||
|
||||
This is how our directory structure should look now:
|
||||
At this point, our directory structure should look like this:
|
||||
|
||||
<div class="file-tree">
|
||||
<div class="item">src</div>
|
||||
@@ -207,8 +209,7 @@ This is how our directory structure should look now:
|
||||
|
||||
#### Manual instantiation
|
||||
|
||||
Thus far, we've discussed how Nest automatically handles most of the details of resolving dependencies. In certain circumstances, you may need to step outside of the built-in Dependency Injection system and manually retrieve or instantiate providers. We briefly discuss two such topics below.
|
||||
So far, we've covered how Nest automatically handles most of the details of resolving dependencies. However, in some cases, you might need to step outside of the built-in Dependency Injection system and manually retrieve or instantiate providers. Two such techniques are briefly discussed below.
|
||||
|
||||
To get existing instances, or instantiate providers dynamically, you can use [Module reference](https://docs.nestjs.com/fundamentals/module-ref).
|
||||
|
||||
To get providers within the `bootstrap()` function (for example for standalone applications without controllers, or to utilize a configuration service during bootstrapping) see [Standalone applications](https://docs.nestjs.com/standalone-applications).
|
||||
- To retrieve existing instances or instantiate providers dynamically, you can use the [Module reference](https://docs.nestjs.com/fundamentals/module-ref).
|
||||
- To get providers within the `bootstrap()` function (e.g., for standalone applications or to use a configuration service during bootstrapping), check out [Standalone applications](https://docs.nestjs.com/standalone-applications).
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
### Controllers
|
||||
|
||||
Controllers are responsible for handling incoming **requests** and returning **responses** to the client.
|
||||
Controllers are responsible for handling incoming **requests** and sending **responses** back to the client.
|
||||
|
||||
<figure><img class="illustrative-image" src="/assets/Controllers_1.png" /></figure>
|
||||
|
||||
A controller's purpose is to receive specific requests for the application. The **routing** mechanism controls which controller receives which requests. Frequently, each controller has more than one route, and different routes can perform different actions.
|
||||
A controller's purpose is to handle specific requests for the application. The **routing** mechanism determines which controller will handle each request. Often, a controller has multiple routes, and each route can perform a different action.
|
||||
|
||||
In order to create a basic controller, we use classes and **decorators**. Decorators associate classes with required metadata and enable Nest to create a routing map (tie requests to the corresponding controllers).
|
||||
To create a basic controller, we use classes and **decorators**. Decorators link classes with the necessary metadata, allowing Nest to create a routing map that connects requests to their corresponding controllers.
|
||||
|
||||
> info **Hint** For quickly creating a CRUD controller with the [validation](https://docs.nestjs.com/techniques/validation) built-in, you may use the CLI's [CRUD generator](https://docs.nestjs.com/recipes/crud-generator#crud-generator): `nest g resource [name]`.
|
||||
> info **Hint** To quickly create a CRUD controller with built-in [validation](https://docs.nestjs.com/techniques/validation), you can use the CLI's [CRUD generator](https://docs.nestjs.com/recipes/crud-generator#crud-generator): `nest g resource [name]`.
|
||||
|
||||
#### Routing
|
||||
|
||||
In the following example we'll use the `@Controller()` decorator, which is **required** to define a basic controller. We'll specify an optional route path prefix of `cats`. Using a path prefix in a `@Controller()` decorator allows us to easily group a set of related routes, and minimize repetitive code. For example, we may choose to group a set of routes that manage interactions with a cat entity under the route `/cats`. In that case, we could specify the path prefix `cats` in the `@Controller()` decorator so that we don't have to repeat that portion of the path for each route in the file.
|
||||
In the following example, we’ll use the `@Controller()` decorator, which is **required** to define a basic controller. We'll specify an optional route path prefix of `cats`. Using a path prefix in the `@Controller()` decorator helps us group related routes together and reduces repetitive code. For example, if we want to group routes that manage interactions with a cat entity under the `/cats` path, we can specify the `cats` path prefix in the `@Controller()` decorator. This way, we don't need to repeat that portion of the path for each route in the file.
|
||||
|
||||
```typescript
|
||||
@@filename(cats.controller)
|
||||
@@ -39,11 +39,13 @@ export class CatsController {
|
||||
|
||||
> info **Hint** To create a controller using the CLI, simply execute the `$ nest g controller [name]` command.
|
||||
|
||||
The `@Get()` HTTP request method decorator before the `findAll()` method tells Nest to create a handler for a specific endpoint for HTTP requests. The endpoint corresponds to the HTTP request method (GET in this case) and the route path. What is the route path? The route path for a handler is determined by concatenating the (optional) prefix declared for the controller, and any path specified in the method's decorator. Since we've declared a prefix for every route ( `cats`), and haven't added any path information in the decorator, Nest will map `GET /cats` requests to this handler. As mentioned, the path includes both the optional controller path prefix **and** any path string declared in the request method decorator. For example, a path prefix of `cats` combined with the decorator `@Get('breed')` would produce a route mapping for requests like `GET /cats/breed`.
|
||||
The `@Get()` HTTP request method decorator placed before the `findAll()` method tells Nest to create a handler for a specific endpoint for HTTP requests. This endpoint is defined by the HTTP request method (GET in this case) and the route path. So, what is the route path? The route path for a handler is determined by combining the (optional) prefix declared for the controller with any path specified in the method's decorator. Since we've set a prefix (`cats`) for every route and haven't added any specific path in the method decorator, Nest will map `GET /cats` requests to this handler.
|
||||
|
||||
In our example above, when a GET request is made to this endpoint, Nest routes the request to our user-defined `findAll()` method. Note that the method name we choose here is completely arbitrary. We obviously must declare a method to bind the route to, but Nest doesn't attach any significance to the method name chosen.
|
||||
As mentioned, the route path includes both the optional controller path prefix **and** any path string specified in the method's decorator. For example, if the controller prefix is `cats` and the method decorator is `@Get('breed')`, the resulting route will be `GET /cats/breed`.
|
||||
|
||||
This method will return a 200 status code and the associated response, which in this case is just a string. Why does that happen? To explain, we'll first introduce the concept that Nest employs two **different** options for manipulating responses:
|
||||
In our example above, when a GET request is made to this endpoint, Nest routes the request to the user-defined `findAll()` method. Note that the method name we choose here is entirely arbitrary. While we must declare a method to bind the route to, Nest doesn’t attach any specific significance to the method name.
|
||||
|
||||
This method will return a 200 status code along with the associated response, which in this case is just a string. Why does this happen? To explain, we first need to introduce the concept that Nest uses two **different** options for manipulating responses:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
@@ -71,7 +73,7 @@ This method will return a 200 status code and the associated response, which in
|
||||
|
||||
#### Request object
|
||||
|
||||
Handlers often need access to the client **request** details. Nest provides access to the [request object](https://expressjs.com/en/api.html#req) of the underlying platform (Express by default). We can access the request object by instructing Nest to inject it by adding the `@Req()` decorator to the handler's signature.
|
||||
Handlers often need access to the client’s **request** details. Nest provides access to the [request object](https://expressjs.com/en/api.html#req) from the underlying platform (Express by default). You can access the request object by instructing Nest to inject it using the `@Req()` decorator in the handler’s signature.
|
||||
|
||||
```typescript
|
||||
@@filename(cats.controller)
|
||||
@@ -98,9 +100,9 @@ export class CatsController {
|
||||
}
|
||||
```
|
||||
|
||||
> info **Hint** In order to take advantage of `express` typings (as in the `request: Request` parameter example above), install `@types/express` package.
|
||||
> 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 has properties for the request query string, parameters, HTTP headers, and body (read more [here](https://expressjs.com/en/api.html#req)). In most cases, it's not necessary to grab these properties manually. We can use dedicated decorators instead, such as `@Body()` or `@Query()`, which are available out of the box. Below is a list of the provided decorators and the plain 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 `@Query()`, which are available out of the box. Below is a list of the provided decorators and the corresponding platform-specific objects they represent.
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
@@ -208,7 +210,7 @@ When it comes to asterisks used in the **middle of a route**, Express requires n
|
||||
|
||||
#### Status code
|
||||
|
||||
As mentioned, the response **status code** is always **200** by default, except for POST requests which are **201**. We can easily change this behavior by adding the `@HttpCode(...)` decorator at a handler level.
|
||||
As mentioned, the default **status code** for responses is always **200**, except for POST requests, which default to **201**. You can easily change this behavior by using the `@HttpCode(...)` decorator at the handler level.
|
||||
|
||||
```typescript
|
||||
@Post()
|
||||
@@ -222,7 +224,7 @@ create() {
|
||||
|
||||
Often, your status code isn't static but depends on various factors. In that case, you can use a library-specific **response** (inject using `@Res()`) object (or, in case of an error, throw an exception).
|
||||
|
||||
#### Headers
|
||||
#### Response headers
|
||||
|
||||
To specify a custom response header, you can either use a `@Header()` decorator or a library-specific response object (and call `res.header()` directly).
|
||||
|
||||
@@ -263,7 +265,7 @@ getDocs(@Query('version') version) {
|
||||
|
||||
#### Route parameters
|
||||
|
||||
Routes with static paths won't work when you need to accept **dynamic data** as part of the request (e.g., `GET /cats/1` to get cat with id `1`). In order to define routes with parameters, we can add route parameter **tokens** in the path of the route to capture the dynamic value at that position in the request URL. The route parameter token in the `@Get()` decorator example below demonstrates this usage. Route parameters declared in this way can be accessed using the `@Param()` decorator, which should be added to the method signature.
|
||||
Routes with static paths won’t work when you need to accept **dynamic data** as part of the request (e.g., `GET /cats/1` to get the cat with id `1`). To define routes with parameters, you can add route parameter **tokens** in the route path to capture the dynamic values from the URL. The route parameter token in the `@Get()` decorator example below illustrates this approach. These route parameters can then be accessed using the `@Param()` decorator, which should be added to the method signature.
|
||||
|
||||
> info **Hint** Routes with parameters should be declared after any static paths. This prevents the parameterized paths from intercepting traffic destined for the static paths.
|
||||
|
||||
@@ -283,7 +285,7 @@ findOne(params) {
|
||||
}
|
||||
```
|
||||
|
||||
`@Param()` is used to decorate a method parameter (`params` in the example above), and makes the **route** parameters available as properties of that decorated method parameter inside the body of the method. As seen in the code above, we can access the `id` parameter by referencing `params.id`. You can also pass in a particular parameter token to the decorator, and then reference the route parameter directly by name in the method body.
|
||||
The `@Param()` decorator is used to decorate a method parameter (in the example above, `params`), making the **route** parameters accessible as properties of that decorated method parameter inside the method. As shown in the code, you can access the `id` parameter by referencing `params.id`. Alternatively, you can pass a specific parameter token to the decorator and directly reference the route parameter by name within the method body.
|
||||
|
||||
> info **Hint** Import `Param` from the `@nestjs/common` package.
|
||||
|
||||
@@ -301,7 +303,7 @@ findOne(id) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Sub-Domain Routing
|
||||
#### Sub-domain routing
|
||||
|
||||
The `@Controller` decorator can take a `host` option to require that the HTTP host of the incoming requests matches some specific value.
|
||||
|
||||
@@ -329,19 +331,15 @@ export class AccountController {
|
||||
}
|
||||
```
|
||||
|
||||
#### Scopes
|
||||
#### State sharing
|
||||
|
||||
For people coming from different programming language backgrounds, it might be unexpected to learn that in Nest, almost everything is shared across incoming requests. We have a connection pool to the database, singleton services with global state, etc. Remember that Node.js doesn't follow the request/response Multi-Threaded Stateless Model in which every request is processed by a separate thread. Hence, using singleton instances is fully **safe** for our applications.
|
||||
For developers coming from other programming languages, it might be surprising to learn that in Nest, nearly everything is shared across incoming requests. This includes resources like the database connection pool, singleton services with global state, and more. It's important to understand that Node.js doesn't use the request/response Multi-Threaded Stateless Model, where each request is handled by a separate thread. As a result, using singleton instances in Nest is completely **safe** for our applications.
|
||||
|
||||
However, there are edge-cases when request-based lifetime of the controller may be the desired behavior, for instance per-request caching in GraphQL applications, request tracking or multi-tenancy. Learn how to control scopes [here](/fundamentals/injection-scopes).
|
||||
That said, there are specific edge cases where having request-based lifetimes for controllers may be necessary. Examples include per-request caching in GraphQL applications, request tracking, or implementing multi-tenancy. You can learn more about controlling injection scopes [here](/fundamentals/injection-scopes).
|
||||
|
||||
#### Asynchronicity
|
||||
|
||||
We love modern JavaScript and we know that data extraction is mostly **asynchronous**. That's why Nest supports and works well with `async` functions.
|
||||
|
||||
> info **Hint** Learn more about `async / await` feature [here](https://kamilmysliwiec.com/typescript-2-1-introduction-async-await)
|
||||
|
||||
Every async function has to return a `Promise`. This means that you can return a deferred value that Nest will be able to resolve by itself. Let's see an example of this:
|
||||
We love modern JavaScript, especially its emphasis on **asynchronous** data handling. That’s why Nest fully supports `async` functions. Every `async` function must return a `Promise`, which allows you to return a deferred value that Nest can resolve automatically. Here's an example:
|
||||
|
||||
```typescript
|
||||
@@filename(cats.controller)
|
||||
@@ -356,7 +354,7 @@ async findAll() {
|
||||
}
|
||||
```
|
||||
|
||||
The above code is fully valid. Furthermore, Nest route handlers are even more powerful by being able to return RxJS [observable streams](https://rxjs-dev.firebaseapp.com/guide/observable). Nest will automatically subscribe to the source underneath and take the last emitted value (once the stream is completed).
|
||||
This code is perfectly valid. But Nest takes it a step further by allowing route handlers to return RxJS [observable streams](https://rxjs-dev.firebaseapp.com/guide/observable) as well. Nest will handle the subscription internally and resolve the final emitted value once the stream completes.
|
||||
|
||||
```typescript
|
||||
@@filename(cats.controller)
|
||||
@@ -371,13 +369,13 @@ findAll() {
|
||||
}
|
||||
```
|
||||
|
||||
Both of the above approaches work and you can use whatever fits your requirements.
|
||||
Both approaches are valid, and you can choose the one that best suits your needs.
|
||||
|
||||
#### Request payloads
|
||||
|
||||
Our previous example of the POST route handler didn't accept any client params. Let's fix this by adding the `@Body()` decorator here.
|
||||
In our previous example, the POST route handler didn’t accept any client parameters. Let's fix that by adding the `@Body()` decorator.
|
||||
|
||||
But first (if you use TypeScript), we need to determine the **DTO** (Data Transfer Object) schema. A DTO is an object that defines how the data will be sent over the network. We could determine the DTO schema by using **TypeScript** interfaces, or by simple classes. Interestingly, we recommend using **classes** here. Why? Classes are part of the JavaScript ES6 standard, and therefore they are preserved as real entities in the compiled JavaScript. On the other hand, since TypeScript interfaces are removed during the transpilation, Nest can't refer to them at runtime. This is important because features such as **Pipes** enable additional possibilities when they have access to the metatype of the variable at runtime.
|
||||
Before we proceed (if you're using TypeScript), we need to define the **DTO** (Data Transfer Object) schema. A DTO is an object that specifies how data should be sent over the network. We could define the DTO schema using **TypeScript** interfaces or simple classes. However, we recommend using **classes** here. Why? Classes are part of the JavaScript ES6 standard, so they remain intact as real entities in the compiled JavaScript. In contrast, TypeScript interfaces are removed during transpilation, meaning Nest can't reference them at runtime. This is important because features like **Pipes** rely on having access to the metatype of variables at runtime, which is only possible with classes.
|
||||
|
||||
Let's create the `CreateCatDto` class:
|
||||
|
||||
@@ -408,13 +406,62 @@ async create(createCatDto) {
|
||||
|
||||
> info **Hint** Our `ValidationPipe` can filter out properties that should not be received by the method handler. In this case, we can whitelist the acceptable properties, and any property not included in the whitelist is automatically stripped from the resulting object. In the `CreateCatDto` example, our whitelist is the `name`, `age`, and `breed` properties. Learn more [here](https://docs.nestjs.com/techniques/validation#stripping-properties).
|
||||
|
||||
#### 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.
|
||||
|
||||
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) {
|
||||
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:
|
||||
|
||||
```plaintext
|
||||
GET /cats?age=2&breed=Persian
|
||||
```
|
||||
|
||||
would result in `age` being `2` and `breed` being `Persian`.
|
||||
|
||||
If your application requires handling more complex query parameters, such as nested objects or arrays:
|
||||
|
||||
```plaintext
|
||||
?filter[where][name]=John&filter[where][age]=30
|
||||
?item[]=1&item[]=2
|
||||
```
|
||||
|
||||
you'll need to configure your HTTP adapter (Express or Fastify) to use an appropriate query parser. In Express, you can use the `extended` parser, which allows for rich query objects:
|
||||
|
||||
```typescript
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
app.set('query parser', 'extended');
|
||||
```
|
||||
|
||||
In Fastify, you can use the `querystringParser` option:
|
||||
|
||||
```typescript
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
new FastifyAdapter({
|
||||
querystringParser: (str) => qs.parse(str),
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
> info **Hint** `qs` is a querystring parser that supports nesting and arrays. You can install it using `npm install qs`.
|
||||
|
||||
#### Handling errors
|
||||
|
||||
There's a separate chapter about handling errors (i.e., working with exceptions) [here](/exception-filters).
|
||||
|
||||
#### Full resource sample
|
||||
|
||||
Below is an example that makes use of several of the available decorators to create a basic controller. This controller exposes a couple of methods to access and manipulate internal data.
|
||||
Below is an example that demonstrates the use of several available decorators to create a basic controller. This controller provides a few methods to access and manipulate internal data.
|
||||
|
||||
```typescript
|
||||
@@filename(cats.controller)
|
||||
@@ -486,13 +533,13 @@ export class CatsController {
|
||||
}
|
||||
```
|
||||
|
||||
> info **Hint** Nest CLI provides a generator (schematic) that automatically generates **all the boilerplate code** to help us avoid doing all of this, and make the developer experience much simpler. Read more about this feature [here](/recipes/crud-generator).
|
||||
> info **Hint** Nest CLI offers a generator (schematic) that automatically creates **all the boilerplate code**, saving you from doing this manually and improving the overall developer experience. Learn more about this feature [here](/recipes/crud-generator).
|
||||
|
||||
#### Getting up and running
|
||||
|
||||
With the above controller fully defined, Nest still doesn't know that `CatsController` exists and as a result won't create an instance of this class.
|
||||
Even with the `CatsController` fully defined, Nest doesn't yet know about it and won't automatically create an instance of the class.
|
||||
|
||||
Controllers always belong to a module, which is why we include the `controllers` array within the `@Module()` decorator. Since we haven't yet defined any other modules except the root `AppModule`, we'll use that to introduce the `CatsController`:
|
||||
Controllers must always be part of a module, which is why we include the `controllers` array within the `@Module()` decorator. Since we haven’t defined any other modules apart from the root `AppModule`, we’ll use it to register the `CatsController`:
|
||||
|
||||
```typescript
|
||||
@@filename(app.module)
|
||||
@@ -505,11 +552,11 @@ import { CatsController } from './cats/cats.controller';
|
||||
export class AppModule {}
|
||||
```
|
||||
|
||||
We attached the metadata to the module class using the `@Module()` decorator, and Nest can now easily reflect which controllers have to be mounted.
|
||||
We attached the metadata to the module class using the `@Module()` decorator, and now Nest can easily determine which controllers need to be mounted.
|
||||
|
||||
#### Library-specific approach
|
||||
|
||||
So far we've discussed the Nest standard way of manipulating responses. The second way of manipulating the response is to use a library-specific [response object](https://expressjs.com/en/api.html#res). In order to inject a particular response object, we need to use the `@Res()` decorator. To show the differences, let's rewrite the `CatsController` to the following:
|
||||
So far, we've covered the standard Nest way of manipulating responses. Another approach is to use a library-specific [response object](https://expressjs.com/en/api.html#res). To inject a specific response object, we can use the `@Res()` decorator. To highlight the differences, let’s rewrite the `CatsController` like this:
|
||||
|
||||
```typescript
|
||||
@@filename()
|
||||
@@ -547,9 +594,9 @@ export class CatsController {
|
||||
}
|
||||
```
|
||||
|
||||
Though this approach works, and does in fact allow for more flexibility in some ways by providing full control of the response object (headers manipulation, library-specific features, and so on), it should be used with care. In general, the approach is much less clear and does have some disadvantages. The main disadvantage is that your code becomes platform-dependent (as underlying libraries may have different APIs on the response object), and harder to test (you'll have to mock the response object, etc.).
|
||||
While this approach works and offers more flexibility by giving full control over the response object (such as header manipulation and access to library-specific features), it should be used with caution. Generally, this method is less clear and comes with some downsides. The main disadvantage is that your code becomes platform-dependent, as different underlying libraries may have different APIs for the response object. Additionally, it can make testing more challenging, as you'll need to mock the response object, among other things.
|
||||
|
||||
Also, in the example above, you lose compatibility with Nest features that depend on Nest standard response handling, such as Interceptors and `@HttpCode()` / `@Header()` decorators. To fix this, you can set the `passthrough` option to `true`, as follows:
|
||||
Furthermore, by using this approach, you lose compatibility with Nest features that rely on standard response handling, such as Interceptors and the `@HttpCode()` / `@Header()` decorators. To address this, you can enable the `passthrough` option like this:
|
||||
|
||||
```typescript
|
||||
@@filename()
|
||||
@@ -567,4 +614,4 @@ findAll(res) {
|
||||
}
|
||||
```
|
||||
|
||||
Now you can interact with the native response object (for example, set cookies or headers depending on certain conditions), but leave the rest to the framework.
|
||||
With this approach, you can interact with the native response object (for example, setting cookies or headers based on specific conditions), while still allowing the framework to handle the rest.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
### Modules
|
||||
|
||||
A module is a class annotated with a `@Module()` decorator. The `@Module()` decorator provides metadata that **Nest** makes use of to organize the application structure.
|
||||
A module is a class that is annotated with the `@Module()` decorator. This decorator provides metadata that **Nest** uses to organize and manage the application structure efficiently.
|
||||
|
||||
<figure><img class="illustrative-image" src="/assets/Modules_1.png" /></figure>
|
||||
|
||||
Each application has at least one module, a **root module**. The root module is the starting point Nest uses to build the **application graph** - the internal data structure Nest uses to resolve module and provider relationships and dependencies. While very small applications may theoretically have just the root module, this is not the typical case. We want to emphasize that modules are **strongly** recommended as an effective way to organize your components. Thus, for most applications, the resulting architecture will employ multiple modules, each encapsulating a closely related set of **capabilities**.
|
||||
Every Nest application has at least one module, the **root module**, which serves as the starting point for Nest to build the **application graph**. This graph is an internal structure that Nest uses to resolve relationships and dependencies between modules and providers. While small applications might only have a root module, this is generally not the case. Modules are **highly recommended** as an effective way to organize your components. For most applications, you'll likely have multiple modules, each encapsulating a closely related set of **capabilities**.
|
||||
|
||||
The `@Module()` decorator takes a single object whose properties describe the module:
|
||||
The `@Module()` decorator takes a single object with properties that describe the module:
|
||||
|
||||
| | |
|
||||
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -15,13 +15,13 @@ The `@Module()` decorator takes a single object whose properties describe the mo
|
||||
| `imports` | the list of imported modules that export the providers which are required in this module |
|
||||
| `exports` | the subset of `providers` that are provided by this module and should be available in other modules which import this module. You can use either the provider itself or just its token (`provide` value) |
|
||||
|
||||
The module **encapsulates** providers by default. This means that it's impossible to inject providers that are neither directly part of the current module nor exported from the imported modules. Thus, you may consider the exported providers from a module as the module's public interface, or API.
|
||||
The module **encapsulates** providers by default, meaning you can only inject providers that are either part of the current module or explicitly exported from other imported modules. The exported providers from a module essentially serve as the module's public interface or API.
|
||||
|
||||
#### Feature modules
|
||||
#### Feature Modules
|
||||
|
||||
The `CatsController` and `CatsService` belong to the same application domain. As they are closely related, it makes sense to move them into a feature module. A feature module simply organizes code relevant for a specific feature, keeping code organized and establishing clear boundaries. This helps us manage complexity and develop with [SOLID](https://en.wikipedia.org/wiki/SOLID) principles, especially as the size of the application and/or team grows.
|
||||
In our example, the `CatsController` and `CatsService` are closely related and serve the same application domain. It makes sense to group them into a feature module. A feature module organizes code that is relevant to a specific feature, helping to maintain clear boundaries and better organization. This is particularly important as the application or team grows, and it aligns with the [SOLID](https://en.wikipedia.org/wiki/SOLID) principles.
|
||||
|
||||
To demonstrate this, we'll create the `CatsModule`.
|
||||
Next, we'll create the `CatsModule` to demonstrate how to group the controller and service.
|
||||
|
||||
```typescript
|
||||
@@filename(cats/cats.module)
|
||||
@@ -175,13 +175,11 @@ export class CatsModule {}
|
||||
|
||||
The `@Global()` decorator makes the module global-scoped. Global modules should be registered **only once**, generally by the root or core module. In the above example, the `CatsService` provider will be ubiquitous, and modules that wish to inject the service will not need to import the `CatsModule` in their imports array.
|
||||
|
||||
> info **Hint** Making everything global is not a good design decision. Global modules are available to reduce the amount of necessary boilerplate. The `imports` array is generally the preferred way to make the module's API available to consumers.
|
||||
> info **Hint** Making everything global is not recommended as a design practice. While global modules can help reduce boilerplate, it's generally better to use the `imports` array to make a module's API available to other modules in a controlled and clear way. This approach provides better structure and maintainability, ensuring that only the necessary parts of the module are shared with others while avoiding unnecessary coupling between unrelated parts of the application.
|
||||
|
||||
#### Dynamic modules
|
||||
|
||||
The Nest module system includes a powerful feature called **dynamic modules**. This feature enables you to easily create customizable modules that can register and configure providers dynamically. Dynamic modules are covered extensively [here](/fundamentals/dynamic-modules). In this chapter, we'll give a brief overview to complete the introduction to modules.
|
||||
|
||||
Following is an example of a dynamic module definition for a `DatabaseModule`:
|
||||
Dynamic modules in Nest allow you to create modules that can be configured at runtime. This is especially useful when you need to provide flexible, customizable modules where the providers can be created based on certain options or configurations. Here's a brief overview of how **dynamic modules** work.
|
||||
|
||||
```typescript
|
||||
@@filename()
|
||||
|
||||
Reference in New Issue
Block a user