Skip to content

Commit f481ee0

Browse files
2 parents 439a518 + d6aeb14 commit f481ee0

File tree

17 files changed

+136
-53
lines changed

17 files changed

+136
-53
lines changed

content/exception-filters.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ You can add as many filters with this technique as needed; simply add each to th
284284

285285
In order to catch **every** unhandled exception (regardless of the exception type), leave the `@Catch()` decorator's parameter list empty, e.g., `@Catch()`.
286286

287+
In the example below we have a code that is platform-agnostic because it uses the [HTTP adapter](./faq/http-adapter) to deliver the response, and doesn't use any of the platform-specific objects (`Request` and `Response`) directly:
288+
287289
```typescript
288290
import {
289291
ExceptionFilter,
@@ -292,30 +294,35 @@ import {
292294
HttpException,
293295
HttpStatus,
294296
} from '@nestjs/common';
297+
import { HttpAdapterHost } from '@nestjs/core';
295298

296299
@Catch()
297300
export class AllExceptionsFilter implements ExceptionFilter {
298-
catch(exception: unknown, host: ArgumentsHost) {
301+
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
302+
303+
catch(exception: unknown, host: ArgumentsHost): void {
304+
// In certain situations `httpAdapter` might not be available in the
305+
// constructor method, thus we should resolve it here.
306+
const { httpAdapter } = this.httpAdapterHost;
307+
299308
const ctx = host.switchToHttp();
300-
const response = ctx.getResponse();
301-
const request = ctx.getRequest();
302309

303-
const status =
310+
const httpStatus =
304311
exception instanceof HttpException
305312
? exception.getStatus()
306313
: HttpStatus.INTERNAL_SERVER_ERROR;
307314

308-
response.status(status).json({
309-
statusCode: status,
315+
const responseBody = {
316+
statusCode: httpStatus,
310317
timestamp: new Date().toISOString(),
311-
path: request.url,
312-
});
318+
path: httpAdapter.getRequestUrl(ctx.getRequest()),
319+
};
320+
321+
httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
313322
}
314323
}
315324
```
316325

317-
In the example above the filter will catch each exception thrown, regardless of its type (class).
318-
319326
#### Inheritance
320327

321328
Typically, you'll create fully customized exception filters crafted to fulfill your application requirements. However, there might be use-cases when you would like to simply extend the built-in default **global exception filter**, and override the behavior based on certain factors.

content/faq/errors.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ There are a few gotchas, that are common. One is putting a provider in an `impor
2424
2525
If you run across this error while developing, take a look at the module mentioned in the error message and look at its `providers`. For each provider in the `providers` array, make sure the module has access to all of the dependencies. Often times, `providers` are duplicated in a "Feature Module" and a "Root Module" which means Nest will try to instantiate the provider twice. More than likely, the module containing the `provider` being duplicated should be added in the "Root Module"'s `imports` array instead.
2626

27+
If the `unknown_token` above is the string `dependency`, you might have a circular file import. This is different from the [circular dependency](./errors.md#circular-dependency-error) below because instead of having providers depend on each other in their constructors, it just means that two files end up importing each other. A common case would be a module file declaring a token and importing a provider, and the provider import the token constant from the module file. If you are using barrel files, ensure that your barrel imports do not end up creating these circular imports as well.
28+
2729
#### "Circular dependency" error
2830

2931
Occasionally you'll find it difficult to avoid [circular dependencies](/fundamentals/circular-dependency) in your application. You'll need to take some steps to help Nest resolve these. Errors that arise from circular dependencies look like this:
@@ -41,3 +43,11 @@ Scope [<module_import_chain>]
4143
```
4244

4345
Circular dependencies can arise from both providers depending on each other, or typescript files depending on each other for constants, such as exporting constants from a module file and importing them in a service file. In the latter case, it is advised to create a separate file for your constants. In the former case, please follow the guide on circular dependencies and make sure that both the modules **and** the providers are marked with `forwardRef`.
46+
47+
#### Debugging dependency errors
48+
49+
Along with just manually verifying your dependencies are correct, as of Nest 8.1.0 you can set the `NEST_DEBUG` environment variable to a string that resolves as truthy, and get extra logging information while Nest is resolving all of the dependencies for the application.
50+
51+
<figure><img src="/assets/injector_logs.png" /></figure>
52+
53+
In the above image, the string in yellow is the host class of the dependency being injected, the string in blue is the name of the injected dependency, or its injection token, and the string in purple is the module in which the dependency is being searched for. Using this, you can usually trace back the dependency resolution for what's happening and why you're getting dependency injection problems.

content/fundamentals/dependency-injection.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ What happens when your requirements go beyond those offered by _Standard provide
137137

138138
Nest allows you to define Custom providers to handle these cases. It provides several ways to define custom providers. Let's walk through them.
139139

140+
> info **Hint** If you are having problems with dependency resolution you can set the `NEST_DEBUG` environment variable and get extra dependency resolution logs during startup.
141+
140142
#### Value providers: `useValue`
141143

142144
The `useValue` syntax is useful for injecting a constant value, putting an external library into the Nest container, or replacing a real implementation with a mock object. Let's say you'd like to force Nest to use a mock `CatsService` for testing purposes.

content/fundamentals/unit-testing.md

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,41 @@ Instead of using the production version of any provider, you can override it wit
160160

161161
<app-banner-courses></app-banner-courses>
162162

163+
#### Auto mocking
164+
165+
Nest also allows you to define a mock factory to apply to all of your missing dependencies. This is useful for cases where you have a large number of dependencies in a class and mocking all of them will take a long time and a lot of setup. To make use of this feature, the `createTestingModule()` will need to be chained up with the `useMocker()` method, passing a factory for your dependency mocks. This factory can take in an optional token, which is an instance token, any token which is valid for a Nest provider, and returns a mock implementation. The below is an example of creating a generic mocker using [`jest-mock`](https://www.npmjs.com/package/jest-mock) and a specific mock for `CatsService` using `jest.fn()`.
166+
167+
```typescript
168+
const moduleMocker = new ModuleMocker(global);
169+
170+
describe('CatsController', () => {
171+
let controller: CatsController;
172+
173+
beforeEach(async () => {
174+
const moduleRef = await Test.createTestingModule({
175+
controllers: [CatsController],
176+
})
177+
.useMocker((token) => {
178+
if (token === CatsService) {
179+
return { findAll: jest.fn().mockResolveValue(results) };
180+
}
181+
if (typeof token === 'function') {
182+
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
183+
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
184+
return new Mock();
185+
}
186+
})
187+
.compile();
188+
189+
controller = moduleRef.get(CatsController);
190+
});
191+
})
192+
```
193+
194+
> info **Hint** A general mock factory, like `createMock` from [`@golevelup/ts-jest`](https://github.com/golevelup/nestjs/tree/master/packages/testing) can also be passed directly.
195+
196+
You can also retrieve these mocks out of the testing container as you normally would custom providers, `moduleRef.get(CatsService)`.
197+
163198
#### End-to-end testing
164199

165200
Unlike unit testing, which focuses on individual modules and classes, end-to-end (e2e) testing covers the interaction of classes and modules at a more aggregate level -- closer to the kind of interaction that end-users will have with the production system. As an application grows, it becomes hard to manually test the end-to-end behavior of each API endpoint. Automated end-to-end tests help us ensure that the overall behavior of the system is correct and meets project requirements. To perform e2e tests we use a similar configuration to the one we just covered in **unit testing**. In addition, Nest makes it easy to use the [Supertest](https://github.com/visionmedia/supertest) library to simulate HTTP requests.
@@ -243,26 +278,27 @@ describe('Cats', () => {
243278
>
244279
> ```ts
245280
> let app: NestFastifyApplication;
246-
>
281+
>
247282
> beforeAll(async () => {
248283
> app = moduleRef.createNestApplication<NestFastifyApplication>(
249284
> new FastifyAdapter(),
250285
> );
251286
>
252287
> await app.init();
253288
> await app.getHttpAdapter().getInstance().ready();
254-
> })
255-
>
289+
> });
290+
>
256291
> it(`/GET cats`, () => {
257292
> return app
258293
> .inject({
259294
> method: 'GET',
260-
> url: '/cats'
261-
> }).then(result => {
262-
> expect(result.statusCode).toEqual(200)
263-
> expect(result.payload).toEqual(/* expectedPayload */)
295+
> url: '/cats',
296+
> })
297+
> .then((result) => {
298+
> expect(result.statusCode).toEqual(200);
299+
> expect(result.payload).toEqual(/* expectedPayload */);
264300
> });
265-
> })
301+
> });
266302
> ```
267303
268304
In this example, we build on some of the concepts described earlier. In addition to the `compile()` method we used earlier, we now use the `createNestApplication()` method to instantiate a full Nest runtime environment. We save a reference to the running app in our `app` variable so we can use it to simulate HTTP requests.

content/graphql/federation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ In the next example, we'll set up a demo application with a gateway and two fede
1818
First, install the optional dependency for federation:
1919

2020
```bash
21-
$ npm install --save @apollo/federation
21+
$ npm install --save @apollo/federation @apollo/subgraph
2222
```
2323

2424
#### Schema first

content/graphql/quick-start.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ In this chapter, we assume a basic understanding of GraphQL, and focus on how to
99
Start by installing the required packages:
1010

1111
```bash
12-
$ npm i @nestjs/graphql graphql apollo-server-express
12+
$ npm i @nestjs/graphql graphql@^15 apollo-server-express
1313
```
1414

1515
> info **Hint** If using Fastify, instead of installing `apollo-server-express`, you should install `apollo-server-fastify`.

content/introduction.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ $ npm install
3434
$ npm run start
3535
```
3636

37+
> info **Hint** If you'd like to clone the repository without the git history, you can use [degit](https://github.com/Rich-Harris/degit).
38+
3739
Open your browser and navigate to [`http://localhost:3000/`](http://localhost:3000/).
3840

3941
To install the JavaScript flavor of the starter project, use `javascript-starter.git` in the command sequence above.

content/microservices/grpc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ bidiHello(messages: Observable<any>, metadata: Metadata, call: ServerDuplexStrea
427427
428428
> info **Hint** The `Metadata` and `ServerUnaryCall` classes/interfaces are imported from the `grpc` package.
429429
430-
According to the service definition (in the `.proto` file), the `BidiHello` method should stream requests to the service. To send multiple asynchronous messages to the stream from a client, we leverage an RxJS `ReplySubject` class.
430+
According to the service definition (in the `.proto` file), the `BidiHello` method should stream requests to the service. To send multiple asynchronous messages to the stream from a client, we leverage an RxJS `ReplaySubject` class.
431431

432432
```typescript
433433
const helloService = this.client.getService<HelloService>('HelloService');

content/modules.md

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,12 @@ Each application has at least one module, a **root module**. The root module is
88

99
The `@Module()` decorator takes a single object whose properties describe the module:
1010

11-
<table>
12-
<tr>
13-
<td><code>providers</code></td>
14-
<td>the providers that will be instantiated by the Nest injector and that may be shared at least across this module</td>
15-
</tr>
16-
<tr>
17-
<td><code>controllers</code></td>
18-
<td>the set of controllers defined in this module which have to be instantiated</td>
19-
</tr>
20-
<tr>
21-
<td><code>imports</code></td>
22-
<td>the list of imported modules that export the providers which are required in this module</td>
23-
</tr>
24-
<tr>
25-
<td><code>exports</code></td>
26-
<td>the subset of <code>providers</code> that are provided by this module and should be available in other modules which import this module</td>
27-
</tr>
28-
</table>
11+
| | |
12+
|-|-|
13+
| `providers` | the providers that will be instantiated by the Nest injector and that may be shared at least across this module |
14+
| `controllers` | the set of controllers defined in this module which have to be instantiated |
15+
| `imports` | the list of imported modules that export the providers which are required in this module |
16+
| `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) |
2917

3018
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.
3119

content/security/csrf.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ Start by installing the required package:
1010
$ npm i --save csurf
1111
```
1212

13-
> warning **Warning** As explained on the [csurf middleware page](https://github.com/expressjs/csurf#csurf), the csurf module requires either session middleware or a cookie-parser to be initialized first. Please see that documentation for further instructions.
13+
> warning **Warning** As explained in the [`csurf` docs](https://github.com/expressjs/csurf#csurf), this middleware requires either session middleware or `cookie-parser` to be initialized first. Please see that documentation for further instructions.
1414
15-
Once the installation is complete, apply the csurf middleware as global middleware.
15+
Once the installation is complete, apply the `csurf` middleware as global middleware.
1616

1717
```typescript
1818
import * as csurf from 'csurf';
19+
// ...
1920
// somewhere in your initialization file
2021
app.use(csurf());
2122
```
@@ -32,6 +33,9 @@ Once the installation is complete, register the `fastify-csrf` plugin, as follow
3233

3334
```typescript
3435
import fastifyCsrf from 'fastify-csrf';
35-
// somewhere in your initialization file
36+
// ...
37+
// somewhere in your initialization file after registering some storage plugin
3638
app.register(fastifyCsrf);
3739
```
40+
41+
> warning **Warning** As explained in the `fastify-csrf` docs [here](https://github.com/fastify/fastify-csrf#usage), this plugin requires a storage plugin to be initialized first. Please, see that documentation for further instructions.

0 commit comments

Comments
 (0)