|
1 | 1 | ### Migration guide
|
2 | 2 |
|
3 |
| -This article provides a set of guidelines for migrating from Nest version 6 to version 7. |
| 3 | +This article provides a set of guidelines for migrating from Nest version 7 to version 8. |
| 4 | +To learn more about the new features we've added in the v8, check out this [link](https://github.com/nestjs/nest/pull/6349). |
4 | 5 |
|
5 |
| -#### Custom route decorators |
| 6 | +#### HTTP module |
6 | 7 |
|
7 |
| -The [Custom decorators](/custom-decorators) API has been unified for all types of applications. Now, whether you're creating a GraphQL application or a REST API, the factory passed into the `createParamDecorator()` function will take the `ExecutionContext` (read more [here](/fundamentals/execution-context)) object as a second argument. |
| 8 | +The `HttpModule` exported from the `@nestjs/common` package has been deprecated and will be removed in the next major release. |
| 9 | +Instead, please use the `@nestjs/axios` package (otherwise, there are no API differences). |
8 | 10 |
|
9 |
| -```typescript |
10 |
| -@@filename() |
11 |
| -// Before |
12 |
| -import { createParamDecorator } from '@nestjs/common'; |
| 11 | +#### gRPC strategy |
13 | 12 |
|
14 |
| -export const User = createParamDecorator((data, req) => { |
15 |
| - return req.user; |
16 |
| -}); |
| 13 | +The original Node gRPC library (`grpc`) has been deprecated and will no longer receive feature updates. |
| 14 | +With Nest v8, you should use the `@grpc/grpc-js` library instead. |
17 | 15 |
|
18 |
| -// After |
19 |
| -import { createParamDecorator, ExecutionContext } from '@nestjs/common'; |
| 16 | +#### NATS strategy |
20 | 17 |
|
21 |
| -export const User = createParamDecorator( |
22 |
| - (data: unknown, ctx: ExecutionContext) => { |
23 |
| - const request = ctx.switchToHttp().getRequest(); |
24 |
| - return request.user; |
25 |
| - }, |
26 |
| -); |
27 |
| -@@switch |
28 |
| -// Before |
29 |
| -import { createParamDecorator } from '@nestjs/common'; |
| 18 | +NATS has released a new major version (2.0) which has many changes and it is not API compatible with `[email protected]`. |
| 19 | +If you interact with a Nest microservice (that uses NATS as a transfer layer), from a service written in a different framework, please, see their [migration document](https://github.com/nats-io/nats.js/blob/master/migration.md) to learn what's changed in v2. |
| 20 | +Otherwise, you should not see any specific differences when communicating from one Nest microservice and another (although we use v2 now, there are no API differences - just make sure to upgrade the `nats` package: `npm i nats@latest`). |
30 | 21 |
|
31 |
| -export const User = createParamDecorator((data, req) => { |
32 |
| - return req.user; |
33 |
| -}); |
| 22 | +#### `@All()` decorator |
34 | 23 |
|
35 |
| -// After |
36 |
| -import { createParamDecorator } from '@nestjs/common'; |
| 24 | +Routes annotated with the `@All()` decorator will now map to the `router.all()` method instead of the `router.use()`. |
37 | 25 |
|
38 |
| -export const User = createParamDecorator((data, ctx) => { |
39 |
| - const request = ctx.switchToHttp().getRequest(); |
40 |
| - return request.user; |
41 |
| -}); |
42 |
| -``` |
| 26 | +#### Async listen/start methods |
43 | 27 |
|
44 |
| -#### Microservices |
| 28 | +`listenAsync()` and `startAllMicroservicesAsync()` methods have been deprecated. |
| 29 | +Instead, simply use the `listen()` and `startAllMicroservices()` methods (they are `async` either way). |
45 | 30 |
|
46 |
| -To avoid code duplication, the `MicroserviceOptions` interface has been removed from the `@nestjs/common` package. Therefore, now when you're creating a microservice (through either `createMicroservice()` or `connectMicroservice()` method), you should pass the type generic parameter to get code autocompletion. |
| 31 | +#### Socket.io |
47 | 32 |
|
48 |
| -```typescript |
49 |
| -@@filename() |
50 |
| -// Before |
51 |
| -const app = await NestFactory.createMicroservice(AppModule); |
| 33 | +The `@nestjs/platform-socket.io` package was upgraded to use the `[email protected]` version (Nest v7 was based on the `socket.io` v2). |
| 34 | +To learn more, check out these articles: [Socket.io 3 Release](https://socket.io/blog/socket-io-3-release/) and [Socket.io 4 Release](https://socket.io/blog/socket-io-4-release/). |
52 | 35 |
|
53 |
| -// After |
54 |
| -const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule); |
55 |
| -@@switch |
56 |
| -// Before |
57 |
| -const app = await NestFactory.createMicroservice(AppModule); |
| 36 | +#### `@nestjs/config` package |
58 | 37 |
|
59 |
| -// After |
60 |
| -const app = await NestFactory.createMicroservice(AppModule); |
61 |
| -``` |
62 |
| - |
63 |
| -> info **Hint** The `MicroserviceOptions` interface is exported from the `@nestjs/microservices` package. |
64 |
| -
|
65 |
| -#### GraphQL |
66 |
| - |
67 |
| -In the version 6 major release of NestJS, we introduced the code-first approach as a compatibility layer between the `type-graphql` package and the `@nestjs/graphql` module. Eventually, our team decided to reimplement all the features from scratch due to a lack of flexibility. To avoid numerous breaking changes, the public API is backward-compatible and may resemble `type-graphql`. |
68 |
| - |
69 |
| -In order to migrate your existing application, simply rename all the `type-graphql` imports to the `@nestjs/graphql`. If you used more advanced features, you might need to also: |
70 |
| - |
71 |
| -- use `Type` (imported from `@nestjs/common`) instead of `ClassType` (imported from `type-graphql`) |
72 |
| -- move methods that require `@Args()` from object types (classes annotated with `@ObjectType()` decorator) under resolver classes (and use `@ResolveField()` decorator instead of `@Field()`) |
73 |
| - |
74 |
| -#### Terminus |
75 |
| - |
76 |
| -In the version 7 major release of `@nestjs/terminus`, a new simplified API has been introduced |
77 |
| -to run health checks. The previously required peer dependency `@godaddy/terminus` has been removed, which allows us to integrate our health checks automatically into Swagger! Read more about the removal of `@godaddy/terminus` [here](https://github.com/nestjs/terminus/issues/340). |
78 |
| - |
79 |
| -For most users, the biggest change will be the removal of the `TerminusModule.forRootAsync` function. With the next major version, this function will be completely removed. |
80 |
| -To migrate to the new API, you will need to create a new controller, which will handle your health checks. |
81 |
| - |
82 |
| -```typescript |
83 |
| -@@filename() |
84 |
| -// Before |
85 |
| -@Injectable() |
86 |
| -export class TerminusOptionsService implements TerminusOptionsFactory { |
87 |
| - constructor( |
88 |
| - private http: HttpHealthIndicator, |
89 |
| - ) {} |
90 |
| - |
91 |
| - createTerminusOptions(): TerminusModuleOptions { |
92 |
| - const healthEndpoint: TerminusEndpoint = { |
93 |
| - url: '/health', |
94 |
| - healthIndicators: [ |
95 |
| - async () => this.http.pingCheck('google', 'https://google.com'), |
96 |
| - ], |
97 |
| - }; |
98 |
| - return { |
99 |
| - endpoints: [healthEndpoint], |
100 |
| - }; |
101 |
| - } |
102 |
| -} |
103 |
| - |
104 |
| -@Module({ |
105 |
| - imports: [ |
106 |
| - TerminusModule.forRootAsync({ |
107 |
| - useClass: TerminusOptionsService |
108 |
| - }) |
109 |
| - ] |
110 |
| -}) |
111 |
| -export class AppModule { } |
112 |
| - |
113 |
| -// After |
114 |
| -@Controller('health') |
115 |
| -export class HealthController { |
116 |
| - constructor( |
117 |
| - private health: HealthCheckService, |
118 |
| - private http: HttpHealthIndicator, |
119 |
| - ) { } |
120 |
| - |
121 |
| - @Get() |
122 |
| - @HealthCheck() |
123 |
| - healthCheck() { |
124 |
| - return this.health.check([ |
125 |
| - async () => this.http.pingCheck('google', 'https://google.com'), |
126 |
| - ]); |
127 |
| - } |
128 |
| -} |
129 |
| - |
130 |
| -@Module({ |
131 |
| - controllers: [ |
132 |
| - HealthController |
133 |
| - ], |
134 |
| - imports: [ |
135 |
| - TerminusModule |
136 |
| - ] |
137 |
| -}) |
138 |
| -export class AppModule { } |
139 |
| - |
140 |
| -@@switch |
141 |
| - |
142 |
| -// Before |
143 |
| -@Injectable() |
144 |
| -@Dependencies(HttpHealthIndicator) |
145 |
| -export class TerminusOptionsService { |
146 |
| - constructor( |
147 |
| - private http, |
148 |
| - ) {} |
149 |
| - |
150 |
| - createTerminusOptions() { |
151 |
| - const healthEndpoint = { |
152 |
| - url: '/health', |
153 |
| - healthIndicators: [ |
154 |
| - async () => this.http.pingCheck('google', 'https://google.com'), |
155 |
| - ], |
156 |
| - }; |
157 |
| - return { |
158 |
| - endpoints: [healthEndpoint], |
159 |
| - }; |
160 |
| - } |
161 |
| -} |
162 |
| - |
163 |
| -@Module({ |
164 |
| - imports: [ |
165 |
| - TerminusModule.forRootAsync({ |
166 |
| - useClass: TerminusOptionsService |
167 |
| - }) |
168 |
| - ] |
169 |
| -}) |
170 |
| -export class AppModule { } |
171 |
| - |
172 |
| -// After |
173 |
| -@Controller('/health') |
174 |
| -@Dependencies(HealthCheckService, HttpHealthIndicator) |
175 |
| -export class HealthController { |
176 |
| - constructor( |
177 |
| - private health, |
178 |
| - private http, |
179 |
| - ) { } |
180 |
| - |
181 |
| - @Get('/') |
182 |
| - @HealthCheck() |
183 |
| - healthCheck() { |
184 |
| - return this.health.check([ |
185 |
| - async () => this.http.pingCheck('google', 'https://google.com'), |
186 |
| - ]) |
187 |
| - } |
188 |
| -} |
189 |
| - |
190 |
| -@Module({ |
191 |
| - controllers: [ |
192 |
| - HealthController |
193 |
| - ], |
194 |
| - imports: [ |
195 |
| - TerminusModule |
196 |
| - ] |
197 |
| -}) |
198 |
| -export class AppModule { } |
199 |
| -``` |
200 |
| - |
201 |
| -> warning **Warning** If you have set a [Global Prefix](faq#global-prefix) in your Nest application and you have not used the `useGlobalPrefix` Terminus option, the URL of your health check will change. Make sure to update the reference to that URL, or use the legacy Terminus API until [nestjs/nest#963](https://github.com/nestjs/nest/issues/963) is fixed. |
202 |
| -
|
203 |
| -If you are forced to use the legacy API, you can also disable deprecation messages for the time being. |
204 |
| - |
205 |
| -```typescript |
206 |
| -TerminusModule.forRootAsync({ |
207 |
| - useFactory: () => ({ |
208 |
| - disableDeprecationWarnings: true, |
209 |
| - endpoints: [ |
210 |
| - // ... |
211 |
| - ] |
212 |
| - }) |
213 |
| -} |
214 |
| -``` |
215 |
| -
|
216 |
| -You should enable shutdown hooks in your `main.ts` file. The Terminus integration will listen on POSIX signals such as SIGTERM (see the [Application shutdown chapter](fundamentals/lifecycle-events#application-shutdown) for more information). When enabled, the health check route(s) will automatically respond with a Service Unavailable (503) HTTP error response when the server is shutting down. |
217 |
| -
|
218 |
| -With the removal of `@godaddy/terminus`, you will need to update your `import` statements |
219 |
| -to use `@nestjs/terminus` instead. Most notable is the import of the `HealthCheckError`. |
220 |
| -
|
221 |
| -```typescript |
222 |
| -@@filename(custom.health) |
223 |
| -// Before |
224 |
| -import { HealthCheckError } from '@godaddy/terminus'; |
225 |
| -// After |
226 |
| -import { HealthCheckError } from '@nestjs/terminus'; |
227 |
| -``` |
228 |
| -
|
229 |
| -Once you have fully migrated, make sure you uninstall `@godaddy/terminus`. |
230 |
| -
|
231 |
| -```bash |
232 |
| -npm uninstall --save @godaddy/terminus |
233 |
| -``` |
234 |
| -
|
235 |
| -##### `DNSHealthIndicator` deprecation |
236 |
| -
|
237 |
| -The `DNSHealthIndicator` has been renamed to `HttpHealthIndicator` in order to improve consistency with the official [`HttpService`](/techniques/http-module#http-module) as well as choosing a better fitting name for its functionality. |
238 |
| -
|
239 |
| -Simply migrate by replacing the `DNSHealthIndicator` references with `HttpHealthIndicator`. The functionality has been untouched. |
240 |
| -
|
241 |
| -```typescript |
242 |
| -// Before |
243 |
| -@Controller('health') |
244 |
| -export class HealthController { |
245 |
| - constructor( |
246 |
| - private dns: DNSHealthIndicator, |
247 |
| - ) { } |
248 |
| - ... |
249 |
| -} |
250 |
| -// After |
251 |
| -@Controller('health') |
252 |
| -export class HealthController { |
253 |
| - constructor( |
254 |
| - private http: HttpHealthIndicator, |
255 |
| - ) { } |
256 |
| - ... |
257 |
| -} |
258 |
| -``` |
259 |
| -
|
260 |
| -#### HTTP exceptions body |
261 |
| -
|
262 |
| -Previously, the generated response bodies for the `HttpException` class and other exceptions derived from it (e.g., `BadRequestException` or `NotFoundException`) were inconsistent. In the latest major release, these exception responses will follow the same structure. |
263 |
| -
|
264 |
| -```typescript |
265 |
| -/* |
266 |
| - * Sample outputs for "throw new ForbiddenException('Forbidden resource')" |
267 |
| - */ |
268 |
| - |
269 |
| -// Before |
270 |
| -{ |
271 |
| - "statusCode": 403, |
272 |
| - "message": "Forbidden resource" |
273 |
| -} |
274 |
| - |
275 |
| -// After |
276 |
| -{ |
277 |
| - "statusCode": 403, |
278 |
| - "message": "Forbidden resource", |
279 |
| - "error": "Forbidden" |
280 |
| -} |
281 |
| -``` |
282 |
| -
|
283 |
| -#### Validation errors schema |
284 |
| -
|
285 |
| -In past releases, the `ValidationPipe` threw an array of the `ValidationError` objects returned by the `class-validator` package. Now, `ValidationPipe` will map errors to a list of plain strings representing error messages. |
286 |
| -
|
287 |
| -```typescript |
288 |
| -// Before |
289 |
| -{ |
290 |
| - "statusCode": 400, |
291 |
| - "error": "Bad Request", |
292 |
| - "message": [ |
293 |
| - { |
294 |
| - "target": {}, |
295 |
| - "property": "email", |
296 |
| - "children": [], |
297 |
| - "constraints": { |
298 |
| - "isEmail": "email must be an email" |
299 |
| - } |
300 |
| - } |
301 |
| - ] |
302 |
| -} |
303 |
| - |
304 |
| -// After |
305 |
| -{ |
306 |
| - "statusCode": 400, |
307 |
| - "message": ["email must be an email"], |
308 |
| - "error": "Bad Request" |
309 |
| -} |
310 |
| -``` |
311 |
| -
|
312 |
| -If you prefer the previous approach, you can restore it by setting the `exceptionFactory` function: |
313 |
| -
|
314 |
| -```typescript |
315 |
| -new ValidationPipe({ |
316 |
| - exceptionFactory: (errors) => new BadRequestException(errors), |
317 |
| -}); |
318 |
| -``` |
319 |
| -
|
320 |
| -#### Implicit type conversion (`ValidationPipe`) |
321 |
| -
|
322 |
| -With the auto-transformation option enabled (`transform: true`), the `ValidationPipe` will now perform conversion of primitive types. In the following example, the `findOne()` method takes one argument which represents an extracted `id` path parameter: |
323 |
| -
|
324 |
| -```typescript |
325 |
| -@Get(':id') |
326 |
| -findOne(@Param('id') id: number) { |
327 |
| - console.log(typeof id === 'number'); // true |
328 |
| - return 'This action returns a user'; |
329 |
| -} |
330 |
| -``` |
331 |
| -
|
332 |
| -By default, every path parameter and query parameter comes over the network as a `string`. In the above example, we specified the `id` type as a `number` (in the method signature). Therefore, the `ValidationPipe` will try to automatically convert a string identifier to a number. |
333 |
| -
|
334 |
| -#### Microservice channels (bidirectional communication) |
335 |
| -
|
336 |
| -To enable the request-response message type, Nest creates two logical channels - one is responsible for transferring the data while the other waits for incoming responses. For some underlying transports, such as NATS, this dual-channel support is provided out-of-the-box. For others, Nest compensates by manually creating separate channels. |
337 |
| -
|
338 |
| -Let's say that we have a single message handler `@MessagePattern('getUsers')`. In the past, Nest built two channels from this pattern: `getUsers_ack` (for requests) and `getUsers_res` (for responses). With version 7, this naming scheme changes. Now Nest will build `getUsers` (for requests) and `getUsers.reply` (for responses) instead. Also, specifically for the MQTT transport strategy, the response channel would be `getUsers/reply` (to avoid conflicts with topic wildcards). |
339 |
| -
|
340 |
| -#### Deprecations |
341 |
| -
|
342 |
| -All deprecations (from Nest version 5 to version 6) have been finally removed (e.g., the deprecated `@ReflectMetadata` decorator). |
343 |
| -
|
344 |
| -#### Node.js |
345 |
| -
|
346 |
| -This release drops support for Node v8. We strongly recommend using the latest LTS version. |
| 38 | +There was a minor breaking change in the `registerAs` function (typings), you can see what has changed in [this PR](https://github.com/nestjs/config/pull/173). |
0 commit comments