|
| 1 | +### Versioning |
| 2 | + |
| 3 | +Versioning allows you to have different versions of your controllers or individual routes running within the same application. Applications change very often and it is not unusual that there are breaking changes that you need to make while still needing to support the previous version of the application. |
| 4 | + |
| 5 | +There are 3 types of versioning that are supported: |
| 6 | +<table> |
| 7 | + <tr> |
| 8 | + <th>Type</th> |
| 9 | + <th>Description</th> |
| 10 | + </tr> |
| 11 | + <tr> |
| 12 | + <td><a href='techniques/versioning#uri-versioning-type'><code>URI Versioning</code></a></td> |
| 13 | + <td>The version will be passed within the URI of the request</td> |
| 14 | + </tr> |
| 15 | + <tr> |
| 16 | + <td><a href='techniques/versioning#header-versioning-type'><code>Header Versioning</code></a></td> |
| 17 | + <td>A custom request header will specify the version</td> |
| 18 | + </tr> |
| 19 | + <tr> |
| 20 | + <td><a href='techniques/versioning#media-type-versioning-type'><code>Media Type Versioning</code></a></td> |
| 21 | + <td>The <code>Accept</code> header of the request will specify the version</td> |
| 22 | + </tr> |
| 23 | +</table> |
| 24 | + |
| 25 | +#### URI Versioning Type |
| 26 | + |
| 27 | +URI Versioning uses the version passed within the URI of the request, such as `https://example.com/v1/route` and `https://example.com/v2/route`. |
| 28 | + |
| 29 | +> warning **Notice** With URI Versioning the version will be automatically added to the URI after the <a href="faq/global-prefix">global path prefix</a> (if one exists), and before any controller or route paths. |
| 30 | +
|
| 31 | +Example HTTP Requests for URI Versioning: |
| 32 | +```http |
| 33 | +GET https://example.com/v1/route HTTP/1.1 |
| 34 | +
|
| 35 | +GET https://example.com/v2/route HTTP/1.1 |
| 36 | +``` |
| 37 | + |
| 38 | +To enable URI Versioning for your application, do the following: |
| 39 | + |
| 40 | +```typescript |
| 41 | +@@filename(main) |
| 42 | +import { VersioningType } from '@nestjs/common'; |
| 43 | + |
| 44 | +async function bootstrap() { |
| 45 | + const app = await NestFactory.create(AppModule); |
| 46 | + app.enableVersioning({ |
| 47 | + type: VersioningType.URI, |
| 48 | + }); |
| 49 | + await app.listen(3000); |
| 50 | +} |
| 51 | +bootstrap(); |
| 52 | +``` |
| 53 | + |
| 54 | +> warning **Notice** The version in the URI will be automatically prefixed with `v` by default, however the prefix value can be configured by setting the `prefix` key to your desired prefix or `false` if you wish to disable it. |
| 55 | +
|
| 56 | +> info **Hint** The `VersioningType` enum is available to use for the `type` property and is imported from the `@nestjs/common` package. |
| 57 | +
|
| 58 | +#### Header Versioning Type |
| 59 | + |
| 60 | +Header Versioning uses a custom, user specified, request header to specify the version where the value of the header will be the version to use for the request. |
| 61 | + |
| 62 | +Example HTTP Requests for Header Versioning: |
| 63 | +```http |
| 64 | +GET https://example.com/route HTTP/1.1 |
| 65 | +Custom-Version-Header: 1 |
| 66 | +
|
| 67 | +GET https://example.com/route HTTP/1.1 |
| 68 | +Custom-Version-Header: 2 |
| 69 | +``` |
| 70 | + |
| 71 | +To enable Header Versioning for your application, do the following: |
| 72 | + |
| 73 | +```typescript |
| 74 | +@@filename(main) |
| 75 | +import { VersioningType } from '@nestjs/common'; |
| 76 | + |
| 77 | +async function bootstrap() { |
| 78 | + const app = await NestFactory.create(AppModule); |
| 79 | + app.enableVersioning({ |
| 80 | + type: VersioningType.HEADER, |
| 81 | + header: 'Custom-Header', |
| 82 | + }); |
| 83 | + await app.listen(3000); |
| 84 | +} |
| 85 | +bootstrap(); |
| 86 | +``` |
| 87 | + |
| 88 | +The `header` property should be the name of the header that will contain the version of the request. |
| 89 | + |
| 90 | +> info **Hint** The `VersioningType` enum is available to use for the `type` property and is imported from the `@nestjs/common` package. |
| 91 | +
|
| 92 | +#### Media Type Versioning Type |
| 93 | + |
| 94 | +Media Type Versioning uses the `Accept` header of the request to specify the version. |
| 95 | + |
| 96 | +Within the `Accept` header, the version will be separated from the media type with a semi-colon, `;`. It should then contain a key-value pair that represents the version to use for the request, such as `Accept: application/json;v=2`. They key is treated more as a prefix when determining the version will to be configured to include the key and separator. |
| 97 | + |
| 98 | +Example HTTP Requests for Media Type Versioning: |
| 99 | +```http |
| 100 | +GET https://example.com/route HTTP/1.1 |
| 101 | +Accept: application/json;v=1 |
| 102 | +
|
| 103 | +GET https://example.com/route HTTP/1.1 |
| 104 | +Accept: application/json;v=2 |
| 105 | +``` |
| 106 | + |
| 107 | +To enable Media Type Versioning for your application, do the following: |
| 108 | + |
| 109 | +```typescript |
| 110 | +@@filename(main) |
| 111 | +import { VersioningType } from '@nestjs/common'; |
| 112 | + |
| 113 | +async function bootstrap() { |
| 114 | + const app = await NestFactory.create(AppModule); |
| 115 | + app.enableVersioning({ |
| 116 | + type: VersioningType.MEDIA_TYPE, |
| 117 | + key: 'v=', |
| 118 | + }); |
| 119 | + await app.listen(3000); |
| 120 | +} |
| 121 | +bootstrap(); |
| 122 | +``` |
| 123 | + |
| 124 | +The `key` property should be the key and separator of the key-value pair that contains the version. For the example `Accept: application/json;v=2`, the `key` property would be set to `v=`. |
| 125 | + |
| 126 | +> info **Hint** The `VersioningType` enum is available to use for the `type` property and is imported from the `@nestjs/common` package. |
| 127 | +
|
| 128 | +#### Usage |
| 129 | + |
| 130 | +Versioning allows you to version controllers, individual routes, and also provides a way for certain resources to opt-out of versioning. The usage of versioning is the same regardless of the Versioning Type your application uses. |
| 131 | + |
| 132 | +> warning **Notice** If versioning is enabled for the application but the controller or route does not specify the version, any requests to that controller/route will be returned a `404` response status. Similarly, if a request is received containing a version that does not have a corresponding controller or route, it will also be returned a `404` response status. |
| 133 | +
|
| 134 | +#### Controller Versions |
| 135 | + |
| 136 | +A version can be applied to a controller, setting the version for all routes within the controller. |
| 137 | + |
| 138 | +To add a version to a controller do the following: |
| 139 | + |
| 140 | +```typescript |
| 141 | +@@filename(cats.controller) |
| 142 | +import { Controller, Get } from '@nestjs/common'; |
| 143 | + |
| 144 | +@Controller({ |
| 145 | + version: '1', |
| 146 | +}) |
| 147 | +export class CatsControllerV1 { |
| 148 | + @Get('cats') |
| 149 | + findAll(): string { |
| 150 | + return 'This action returns all cats for version 1'; |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +@Controller({ |
| 155 | + version: '2', |
| 156 | +}) |
| 157 | +export class CatsControllerV2 { |
| 158 | + @Get('cats') |
| 159 | + findAll(): string { |
| 160 | + return 'This action returns all cats for version 2'; |
| 161 | + } |
| 162 | +} |
| 163 | +@@switch |
| 164 | +import { Controller, Get } from '@nestjs/common'; |
| 165 | + |
| 166 | +@Controller({ |
| 167 | + version: '1', |
| 168 | +}) |
| 169 | +export class CatsControllerV1 { |
| 170 | + @Get('cats') |
| 171 | + findAll() { |
| 172 | + return 'This action returns all cats for version 1'; |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +@Controller({ |
| 177 | + version: '2', |
| 178 | +}) |
| 179 | +export class CatsControllerV2 { |
| 180 | + @Get('cats') |
| 181 | + findAll() { |
| 182 | + return 'This action returns all cats for version 2'; |
| 183 | + } |
| 184 | +} |
| 185 | +``` |
| 186 | + |
| 187 | +#### Route Versions |
| 188 | + |
| 189 | +A version can be applied to an individual route. This version will override any other version that would effect the route, such as the Controller Version. |
| 190 | + |
| 191 | +To add a version to an individual route do the following: |
| 192 | + |
| 193 | +```typescript |
| 194 | +@@filename(cats.controller) |
| 195 | +import { Controller, Get, Version } from '@nestjs/common'; |
| 196 | + |
| 197 | +@Controller() |
| 198 | +export class CatsController { |
| 199 | + @Version('1') |
| 200 | + @Get('cats') |
| 201 | + findAllV1(): string { |
| 202 | + return 'This action returns all cats for version 1'; |
| 203 | + } |
| 204 | + |
| 205 | + @Version('2') |
| 206 | + @Get('cats') |
| 207 | + findAllV2(): string { |
| 208 | + return 'This action returns all cats for version 2'; |
| 209 | + } |
| 210 | +} |
| 211 | +@@switch |
| 212 | +import { Controller, Get, Version } from '@nestjs/common'; |
| 213 | + |
| 214 | +@Controller() |
| 215 | +export class CatsController { |
| 216 | + @Version('1') |
| 217 | + @Get('cats') |
| 218 | + findAllV1() { |
| 219 | + return 'This action returns all cats for version 1'; |
| 220 | + } |
| 221 | + |
| 222 | + @Version('2') |
| 223 | + @Get('cats') |
| 224 | + findAllV2() { |
| 225 | + return 'This action returns all cats for version 2'; |
| 226 | + } |
| 227 | +} |
| 228 | +``` |
| 229 | + |
| 230 | +> info **Hint** The `@Version()` decorator is imported from `@nestjs/common` package. |
| 231 | +
|
| 232 | +#### Multiple Versions |
| 233 | + |
| 234 | +Multiple versions can be applied to a controller or route. To use multiple versions, you would set the version to be an Array. |
| 235 | + |
| 236 | +To add multiple versions do the following: |
| 237 | + |
| 238 | +```typescript |
| 239 | +@@filename(cats.controller) |
| 240 | +import { Controller, Get } from '@nestjs/common'; |
| 241 | + |
| 242 | +@Controller({ |
| 243 | + version: ['1', '2'], |
| 244 | +}) |
| 245 | +export class CatsController { |
| 246 | + @Get('cats') |
| 247 | + findAll(): string { |
| 248 | + return 'This action returns all cats for version 1 or 2'; |
| 249 | + } |
| 250 | +} |
| 251 | +@@switch |
| 252 | +import { Controller, Get } from '@nestjs/common'; |
| 253 | + |
| 254 | +@Controller({ |
| 255 | + version: ['1', '2'], |
| 256 | +}) |
| 257 | +export class CatsController { |
| 258 | + @Get('cats') |
| 259 | + findAll() { |
| 260 | + return 'This action returns all cats for version 1 or 2'; |
| 261 | + } |
| 262 | +} |
| 263 | +``` |
| 264 | + |
| 265 | + |
| 266 | +#### Version Neutral |
| 267 | + |
| 268 | +Some controllers or routes may not care about the version and would have the same functionality regardless of the version. To accommodate this, the version can be set to `VERSION_NEUTRAL` symbol. |
| 269 | + |
| 270 | +An incoming request will be mapped to a `VERSION_NEUTRAL` controller or route regardless of the version sent in the request in addition to if the request does not contain a version at all. |
| 271 | + |
| 272 | +> warning **Notice** For URI Versioning, a `VERSION_NEUTRAL` resource would not have the version present in the URI. |
| 273 | +
|
| 274 | +To add a version neutral controller or route do the following: |
| 275 | + |
| 276 | +```typescript |
| 277 | +@@filename(cats.controller) |
| 278 | +import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common'; |
| 279 | + |
| 280 | +@Controller({ |
| 281 | + version: VERSION_NEUTRAL, |
| 282 | +}) |
| 283 | +export class CatsController { |
| 284 | + @Get('cats') |
| 285 | + findAll(): string { |
| 286 | + return 'This action returns all cats regardless of version'; |
| 287 | + } |
| 288 | +} |
| 289 | +@@switch |
| 290 | +import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common'; |
| 291 | + |
| 292 | +@Controller({ |
| 293 | + version: VERSION_NEUTRAL, |
| 294 | +}) |
| 295 | +export class CatsController { |
| 296 | + @Get('cats') |
| 297 | + findAll() { |
| 298 | + return 'This action returns all cats regardless of version'; |
| 299 | + } |
| 300 | +} |
| 301 | +``` |
| 302 | + |
| 303 | +> info **Hint** The `VERSION_NEUTRAL` symbol is imported from `@nestjs/common` package. |
0 commit comments