Skip to content

Commit d4ce9ca

Browse files
authored
Merge pull request #289 from 19majkel94/params-fixes-n-features
Params fixes and features
2 parents b6ff09d + d7fe496 commit d4ce9ca

File tree

21 files changed

+281
-108
lines changed

21 files changed

+281
-108
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog and release notes
22

3+
### 0.8.0
4+
5+
- rename `@Param` and `@Params` decorators to `@PathParam` and `@PathParams` (#289)
6+
- restore/introduce `@QueryParams()` and `@PathParams()` missing decorators options (they are needed for validation purposes) (#289)
7+
- normalize param object properties (for "queries", "headers", "params" and "cookies") - now you can easily validate query/path params using `class-validator` (#289)
8+
- enhance params normalization - converting from string to primitive types is now more strict and can throw ParamNormalizationError,
9+
e.g. when number is expected but the invalid string (NaN) has been received (#289)
10+
311
### 0.7.2
412

513
- FIXED: Using `@Authorization` decorator with Koa caused 404 responses (ref [#240](https://github.com/pleerock/routing-controllers/pull/240))

README.md

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ You can use routing-controllers with [express.js][1] or [koa.js][2].
128128
}
129129
130130
@Get("/users/:id")
131-
getOne(@Param("id") id: number) {
131+
getOne(@PathParam("id") id: number) {
132132
return "This action returns user #" + id;
133133
}
134134
@@ -138,12 +138,12 @@ You can use routing-controllers with [express.js][1] or [koa.js][2].
138138
}
139139
140140
@Put("/users/:id")
141-
put(@Param("id") id: number, @Body() user: any) {
141+
put(@PathParam("id") id: number, @Body() user: any) {
142142
return "Updating a user...";
143143
}
144144
145145
@Delete("/users/:id")
146-
remove(@Param("id") id: number) {
146+
remove(@PathParam("id") id: number) {
147147
return "Removing user...";
148148
}
149149
@@ -195,7 +195,7 @@ export class UserController {
195195
}
196196
197197
@Get("/users/:id")
198-
getOne(@Param("id") id: number) {
198+
getOne(@PathParam("id") id: number) {
199199
return userRepository.findById(id);
200200
}
201201
@@ -222,7 +222,7 @@ export class UserController {
222222
}
223223
224224
@Get("/users/:id")
225-
getOne(@Param("id") id: number) {
225+
getOne(@PathParam("id") id: number) {
226226
return userRepository.findById(id);
227227
}
228228
@@ -232,12 +232,12 @@ export class UserController {
232232
}
233233
234234
@Put("/users/:id")
235-
put(@Param("id") id: number, @Body() user: User) {
235+
put(@PathParam("id") id: number, @Body() user: User) {
236236
return userRepository.updateById(id, user);
237237
}
238238
239239
@Delete("/users/:id")
240-
remove(@Param("id") id: number) {
240+
remove(@PathParam("id") id: number) {
241241
return userRepository.removeById(id);
242242
}
243243
@@ -346,15 +346,15 @@ export class UserController {
346346

347347
#### Inject routing parameters
348348

349-
You can use `@Param` decorator to inject parameters in your controller actions:
349+
You can use `@PathParam` decorator to inject parameters in your controller actions:
350350

351351
```typescript
352352
@Get("/users/:id")
353-
getOne(@Param("id") id: number) { // id will be automatically casted to "number" because it has type number
353+
getOne(@PathParam("id") id: number) { // id will be automatically casted to "number" because it has type number
354354
}
355355
```
356356

357-
If you want to inject all parameters use `@Params()` decorator.
357+
If you want to inject all parameters use `@PathParams()` decorator.
358358

359359
#### Inject query parameters
360360

@@ -367,6 +367,37 @@ getUsers(@QueryParam("limit") limit: number) {
367367
```
368368

369369
If you want to inject all query parameters use `@QueryParams()` decorator.
370+
The bigest benefit of this approach is that you can perform validation of the params.
371+
372+
```typescript
373+
enum Roles {
374+
Admin = "admin",
375+
User = "user",
376+
Guest = "guest",
377+
}
378+
379+
class GetUsersQuery {
380+
381+
@IsPositive()
382+
limit: number;
383+
384+
@IsAlpha()
385+
city: string;
386+
387+
@IsEnum(Roles)
388+
role: Roles;
389+
390+
@IsBoolean()
391+
isActive: boolean;
392+
393+
}
394+
395+
@Get("/users")
396+
getUsers(@QueryParams() query: GetUsersQuery) {
397+
// here you can access query.role, query.limit
398+
// and others valid query parameters
399+
}
400+
```
370401

371402
#### Inject request body
372403

@@ -584,7 +615,7 @@ To prevent this if you need to specify what status code you want to return using
584615
```typescript
585616
@Delete("/users/:id")
586617
@OnUndefined(204)
587-
async remove(@Param("id") id: number): Promise<void> {
618+
async remove(@PathParam("id") id: number): Promise<void> {
588619
return userRepository.removeById(id);
589620
}
590621
```
@@ -596,7 +627,7 @@ This action will return 404 in the case if user was not found, and regular 200 i
596627
```typescript
597628
@Get("/users/:id")
598629
@OnUndefined(404)
599-
getOne(@Param("id") id: number) {
630+
getOne(@PathParam("id") id: number) {
600631
return userRepository.findOneById(id);
601632
}
602633
```
@@ -616,7 +647,7 @@ export class UserNotFoundError extends HttpError {
616647
```typescript
617648
@Get("/users/:id")
618649
@OnUndefined(UserNotFoundError)
619-
saveUser(@Param("id") id: number) {
650+
saveUser(@PathParam("id") id: number) {
620651
return userRepository.findOneById(id);
621652
}
622653
```
@@ -630,7 +661,7 @@ You can set any custom header in a response:
630661
```typescript
631662
@Get("/users/:id")
632663
@Header("Cache-Control", "none")
633-
getOne(@Param("id") id: number) {
664+
getOne(@PathParam("id") id: number) {
634665
// ...
635666
}
636667
```
@@ -660,7 +691,7 @@ If you want to return errors with specific error codes, there is an easy way:
660691

661692
```typescript
662693
@Get("/users/:id")
663-
getOne(@Param("id") id: number) {
694+
getOne(@PathParam("id") id: number) {
664695

665696
const user = this.userRepository.findOneById(id);
666697
if (!user)
@@ -779,7 +810,7 @@ For example, lets try to use [compression](https://github.com/expressjs/compress
779810

780811
@Get("/users/:id")
781812
@UseBefore(compression())
782-
getOne(@Param("id") id: number) {
813+
getOne(@PathParam("id") id: number) {
783814
// ...
784815
}
785816
```
@@ -871,7 +902,7 @@ Here is example of creating middleware for express.js:
871902
@Get("/users/:id")
872903
@UseBefore(MyMiddleware)
873904
@UseAfter(loggingMiddleware)
874-
getOne(@Param("id") id: number) {
905+
getOne(@PathParam("id") id: number) {
875906
// ...
876907
}
877908
```
@@ -938,7 +969,7 @@ Here is example of creating middleware for koa.js:
938969
@Get("/users/:id")
939970
@UseBefore(MyMiddleware)
940971
@UseAfter(loggingMiddleware)
941-
getOne(@Param("id") id: number) {
972+
getOne(@PathParam("id") id: number) {
942973
// ...
943974
}
944975
```
@@ -1044,7 +1075,7 @@ import {Get, Param, UseInterceptor} from "routing-controllers";
10441075
// in it and return a replaced result. replaced result will be returned to the user
10451076
return content.replace(/Mike/gi, "Michael");
10461077
})
1047-
getOne(@Param("id") id: number) {
1078+
getOne(@PathParam("id") id: number) {
10481079
return "Hello, I am Mike!"; // client will get a "Hello, I am Michael!" response.
10491080
}
10501081
```
@@ -1078,7 +1109,7 @@ import {NameCorrectionInterceptor} from "./NameCorrectionInterceptor";
10781109

10791110
@Get("/users")
10801111
@UseInterceptor(NameCorrectionInterceptor)
1081-
getOne(@Param("id") id: number) {
1112+
getOne(@PathParam("id") id: number) {
10821113
return "Hello, I am Mike!"; // client will get a "Hello, I am Michael!" response.
10831114
}
10841115
```
@@ -1142,7 +1173,7 @@ export class UserController {
11421173
If `User` is an interface - then simple literal object will be created.
11431174
If its a class - then instance of this class will be created.
11441175

1145-
This technique works not only with `@Body`, but also with `@Param`, `@QueryParam`, `@BodyParam` and other decorators.
1176+
This technique works not only with `@Body`, but also with `@PathParam`, `@QueryParam`, `@BodyParam` and other decorators.
11461177
Learn more about class-transformer and how to handle more complex object constructions [here][4].
11471178
This behaviour is enabled by default.
11481179
If you want to disable it simply pass `classTransformer: false` to createExpressServer method.
@@ -1203,7 +1234,7 @@ an error will be thrown and captured by routing-controller, so the client will r
12031234
12041235
If you need special options for validation (groups, skipping missing properties, etc.) or transforming (groups, excluding prefixes, versions, etc.), you can pass them as global config as `validation ` in createExpressServer method or as a local `validate` setting for method parameter - `@Body({ validate: localOptions })`.
12051236
1206-
This technique works not only with `@Body` but also with `@Param`, `@QueryParam`, `@BodyParam` and other decorators.
1237+
This technique works not only with `@Body` but also with `@PathParam`, `@QueryParam`, `@BodyParam` and other decorators.
12071238
12081239
## Using authorization features
12091240
@@ -1397,8 +1428,8 @@ export class QuestionController {
13971428
| `@Req()` | `getAll(@Req() request: Request)` | Injects a Request object. | `function (request, response)` |
13981429
| `@Res()` | `getAll(@Res() response: Response)` | Injects a Response object. | `function (request, response)` |
13991430
| `@Ctx()` | `getAll(@Ctx() context: Context)` | Injects a Context object (koa-specific) | `function (ctx)` (koa-analogue) |
1400-
| `@Param(name: string, options?: ParamOptions)` | `get(@Param("id") id: number)` | Injects a router parameter. | `request.params.id` |
1401-
| `@Params()` | `get(@Params() params: any)` | Injects all request parameters. | `request.params` |
1431+
| `@PathParam(name: string, options?: ParamOptions)` | `get(@PathParam("id") id: number)` | Injects a router parameter. | `request.params.id` |
1432+
| `@PathParams()` | `get(@PathParams() params: any)` | Injects all request parameters. | `request.params` |
14021433
| `@QueryParam(name: string, options?: ParamOptions)` | `get(@QueryParam("id") id: number)` | Injects a query string parameter. | `request.query.id` |
14031434
| `@QueryParams()` | `get(@QueryParams() params: any)` | Injects all query parameters. | `request.query` |
14041435
| `@HeaderParam(name: string, options?: ParamOptions)` | `get(@HeaderParam("token") token: string)` | Injects a specific request headers. | `request.headers.token` |

sample/sample11-complete-sample-express/modules/question/controllers/QuestionController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Request} from "express";
22
import {JsonController} from "../../../../../src/decorator/JsonController";
33
import {Get} from "../../../../../src/decorator/Get";
4-
import {Param} from "../../../../../src/decorator/Param";
4+
import {PathParam} from "../../../../../src/decorator/PathParam";
55
import {Post} from "../../../../../src/decorator/Post";
66
import {Req} from "../../../../../src/decorator/Req";
77
import {Put} from "../../../../../src/decorator/Put";
@@ -20,7 +20,7 @@ export class QuestionController {
2020
}
2121

2222
@Get("/questions/:id")
23-
getOne(@Param("id") id: number) {
23+
getOne(@PathParam("id") id: number) {
2424
if (!id)
2525
return Promise.reject(new Error("No id is specified"));
2626

sample/sample12-session-support/UserController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {Post} from "../../src/decorator/Post";
77
import {Put} from "../../src/decorator/Put";
88
import {Patch} from "../../src/decorator/Patch";
99
import {Delete} from "../../src/decorator/Delete";
10-
import {Param} from "../../src/decorator/Param";
10+
import {PathParam} from "../../src/decorator/PathParam";
1111
import {Session} from "../../src/decorator/Session";
1212
import {ContentType} from "../../src/decorator/ContentType";
1313

@@ -36,7 +36,7 @@ export class UserController {
3636
}
3737

3838
@Put("/users/:id")
39-
put(@Param("id") id: number, @Session() session: Express.Session) {
39+
put(@PathParam("id") id: number, @Session() session: Express.Session) {
4040
(session as any).user = { name: "test", number: id };
4141
return "User has been putted!";
4242
}

sample/sample4-extra-parameters/BlogController.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {Put} from "../../src/decorator/Put";
55
import {Patch} from "../../src/decorator/Patch";
66
import {Delete} from "../../src/decorator/Delete";
77
import {QueryParam} from "../../src/decorator/QueryParam";
8-
import {Param} from "../../src/decorator/Param";
8+
import {PathParam} from "../../src/decorator/PathParam";
99
import {Body} from "../../src/decorator/Body";
1010

1111
export interface BlogFilter {
@@ -26,7 +26,7 @@ export class BlogController {
2626
}
2727

2828
@Get("/blogs/:id")
29-
getOne(@Param("id") id: number, @QueryParam("name") name: string) {
29+
getOne(@PathParam("id") id: number, @QueryParam("name") name: string) {
3030
return { id: id, name: name };
3131
}
3232

@@ -36,17 +36,17 @@ export class BlogController {
3636
}
3737

3838
@Put("/blogs/:id")
39-
put(@Param("id") id: number) {
39+
put(@PathParam("id") id: number) {
4040
return "Blog #" + id + " has been putted!";
4141
}
4242

4343
@Patch("/blogs/:id")
44-
patch(@Param("id") id: number) {
44+
patch(@PathParam("id") id: number) {
4545
return "Blog #" + id + " has been patched!";
4646
}
4747

4848
@Delete("/blogs/:id")
49-
remove(@Param("id") id: number) {
49+
remove(@PathParam("id") id: number) {
5050
return "Blog #" + id + " has been removed!";
5151
}
5252

sample/sample6-global-middlewares/BlogController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {ForbiddenError} from "../../src/http-error/ForbiddenError";
22
import {Controller} from "../../src/decorator/Controller";
33
import {Get} from "../../src/decorator/Get";
4-
import {Param} from "../../src/decorator/Param";
4+
import {PathParam} from "../../src/decorator/PathParam";
55
import {ContentType} from "../../src/decorator/ContentType";
66

77
@Controller()
@@ -19,7 +19,7 @@ export class BlogController {
1919

2020
@Get("/blogs/:id")
2121
@ContentType("application/json")
22-
getOne(@Param("id") id: number) {
22+
getOne(@PathParam("id") id: number) {
2323
if (!id)
2424
throw new ForbiddenError();
2525

sample/sample9-use-and-middlewares/BlogController.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {JsonController} from "../../src/decorator/JsonController";
22
import {Get} from "../../src/decorator/Get";
3-
import {Param} from "../../src/decorator/Param";
3+
import {PathParam} from "../../src/decorator/PathParam";
44
import {CompressionMiddleware} from "./CompressionMiddleware";
55
import {AllControllerActionsMiddleware} from "./AllControllerActionsMiddleware";
66
import {UseBefore} from "../../src/decorator/UseBefore";
@@ -24,7 +24,7 @@ export class BlogController {
2424
}
2525

2626
@Get("/blogs/:id")
27-
getOne(@Param("id") id: number) {
27+
getOne(@PathParam("id") id: number) {
2828
return { id: id, firstName: "First", secondName: "blog" };
2929
}
3030

0 commit comments

Comments
 (0)