Skip to content

Commit d5205a6

Browse files
authored
Merge branch 'master' into alexishr-uses-nestjs
2 parents 6cb48d4 + e1b60cf commit d5205a6

36 files changed

+2800
-7329
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ dist/*
4040
npm-debug.log
4141
testem.log
4242
/typings
43-
43+
.angular
4444
# e2e
4545
/e2e/*.js
4646
/e2e/*.map

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(The MIT License)
22

3-
Copyright (c) 2017 Kamil Myśliwiec <http://kamilmysliwiec.com>
3+
Copyright (c) 2017-2022 Kamil Myśliwiec <http://kamilmysliwiec.com>
44

55
Permission is hereby granted, free of charge, to any person obtaining
66
a copy of this software and associated documentation files (the

angular.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"src/_redirects"
2828
],
2929
"styles": [
30-
"src/styles.scss"
30+
"src/styles.scss",
31+
"src/assets/css/perfect-scrollbar.min.css"
3132
]
3233
},
3334
"configurations": {

content/discover/who-uses.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@
254254
"https://forwardigital.co.uk",
255255
"https://rozetka.com.ua",
256256
"https://www.itrio.net",
257-
"https://alexishr.com"
257+
"https://alexishr.com",
258+
"https://dyrector.io",
259+
"https://stijlbreuk.nl"
258260
]
259261
}

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/serverless.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ First, let's install the required packages:
178178

179179
```bash
180180
$ npm i @vendia/serverless-express aws-lambda
181-
$ npm i @types/aws-lambda serverless-offline
181+
$ npm i -D @types/aws-lambda serverless-offline
182182
```
183183

184184
> info **Hint** To speed up development cycles, we install the `serverless-offline` plugin which emulates AWS λ and API Gateway.
@@ -263,7 +263,7 @@ $ npx serverless offline
263263
Once the application is running, open your browser and navigate to `http://localhost:3000/dev/[ANY_ROUTE]` (where `[ANY_ROUTE]` is any endpoint registered in your application).
264264

265265
In the sections above, we've shown that using `webpack` and bundling your app can have significant impact on the overall bootstrap time.
266-
However, to make it work with our example, there's one additional configuration you must add in your `webpack.config.js` file. Generally,
266+
However, to make it work with our example, there are a few additional configurations you must add in your `webpack.config.js` file. Generally,
267267
to make sure our `handler` function will be picked up, we must change the `output.libraryTarget` property to `commonjs2`.
268268

269269
```javascript
@@ -280,6 +280,31 @@ return {
280280

281281
With this in place, you can now use `$ nest build --webpack` to compile your function's code (and then `$ npx serverless offline` to test it).
282282

283+
It's also recommended (but **not required** as it will slow down your build process) to install the `terser-webpack-plugin` package and override its configuration to keep classnames intact when minifying your production build. Not doing so can result in incorrect behavior when using `class-validator` within your application.
284+
285+
```javascript
286+
const TerserPlugin = require('terser-webpack-plugin');
287+
288+
return {
289+
...options,
290+
externals: [],
291+
optimization: {
292+
minimizer: [
293+
new TerserPlugin({
294+
terserOptions: {
295+
keep_classnames: true,
296+
},
297+
}),
298+
],
299+
},
300+
output: {
301+
...options.output,
302+
libraryTarget: 'commonjs2',
303+
},
304+
// ... the rest of the configuration
305+
};
306+
```
307+
283308
#### Using standalone application feature
284309

285310
Alternatively, if you want to keep your function very lightweight and you don't need any HTTP-related features (routing, but also guards, interceptors, pipes, etc.),

content/fundamentals/unit-testing.md

Lines changed: 48 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,31 @@ 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+
> });
302+
>
303+
> afterAll(async () => {
304+
> await app.close();
305+
> });
266306
> ```
267307
268308
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ import { UsersService } from './users.service'; // Not included in this example
136136
export class AppModule {}
137137
```
138138

139+
#### Example
140+
141+
A working example is available [here](https://github.com/nestjs/nest/tree/master/sample/31-graphql-federation-code-first/users-application) in code first mode and [here](https://github.com/nestjs/nest/tree/master/sample/32-graphql-federation-schema-first/users-application) in schema first mode.
142+
139143
#### Federated example: Posts
140144

141145
Our Post service serves aggregated posts via a `getPosts` query, but also extends our `User` type with `user.posts`
@@ -318,6 +322,9 @@ import { PostsService } from './posts.service'; // Not included in example
318322
})
319323
export class AppModule {}
320324
```
325+
#### Example
326+
327+
A working example is available [here](https://github.com/nestjs/nest/tree/master/sample/31-graphql-federation-code-first/posts-application) for the code first mode and [here](https://github.com/nestjs/nest/tree/master/sample/32-graphql-federation-schema-first/posts-application) for the schema first mode.
321328

322329
#### Federated example: Gateway
323330

@@ -354,6 +361,10 @@ export class AppModule {}
354361

355362
> info **Hint** Apollo recommends that you don't rely on the service discovery in a production environment but use their [Graph Manager](https://www.apollographql.com/docs/graph-manager/federation/) instead.
356363
364+
#### Example
365+
366+
A working example is available [here](https://github.com/nestjs/nest/tree/master/sample/31-graphql-federation-code-first/gateway) for the code first mode and [here](https://github.com/nestjs/nest/tree/master/sample/32-graphql-federation-schema-first/gateway) for the schema first mode.
367+
357368
#### Sharing context
358369

359370
You can customize the requests between the gateway and federated services using a build service. This allows you to share context about the request. You can easily extend the default `RemoteGraphQLDataSource` and implement one of the hooks. Please refer to [Apollo Docs](https://www.apollographql.com/docs/apollo-server/api/apollo-gateway/#remotegraphqldatasource) on `RemoteGraphQLDataSource` for more information about the possibilities.

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/graphql/subscriptions.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,14 @@ If you're using the `graphql-ws` package, the signature of the `onConnect` callb
334334
subscriptions: {
335335
'graphql-ws': {
336336
onConnect: (context: Context<any>) => {
337-
const { connectionParams } = context;
338-
// the rest will remain the same as in the example above
337+
const { connectionParams, extra } = context;
338+
// user validation will remain the same as in the example above
339+
// when using with graphql-ws, additional context value should be stored in the extra field
340+
extra.user = { user: {} };
339341
},
340342
},
343+
context: ({ extra }) => {
344+
// you can now access your additional context value through the extra field
345+
}
341346
},
342347
```

0 commit comments

Comments
 (0)