Skip to content

Commit be17c80

Browse files
author
Aleksi Pekkala
committed
Implement route/controller-specific transform options
1 parent 0fbe188 commit be17c80

25 files changed

+324
-113
lines changed

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ You can use routing-controllers with [express.js][1] or [koa.js][2].
4242
- [Throw HTTP errors](#throw-http-errors)
4343
- [Enable CORS](#enable-cors)
4444
- [Default settings](#default-settings)
45+
- [Selectively disabling request/response transform](#selectively-disable-requestresponse-transforming)
4546
* [Using middlewares](#using-middlewares)
4647
+ [Use exist middleware](#use-exist-middleware)
4748
+ [Creating your own express middleware](#creating-your-own-express-middleware)
@@ -509,10 +510,6 @@ If you specify a class type to parameter that is decorated with parameter decora
509510
routing-controllers will use [class-transformer][4] to create instance of that class type.
510511
More info about this feature is available [here](#creating-instances-of-classes-from-action-params).
511512

512-
#### Disable response transformation
513-
514-
By default response values are coerced to plain objects with [class-transformer](https://github.com/pleerock/class-transformer). When returning large objects or values with complex serialization logic (e.g. Mongoose documents) you might opt for the default `toJSON` handler instead. To disable response transformation simply pass `useResponseClassTransformer: false` to createExpressServer method.
515-
516513
#### Set custom ContentType
517514

518515
You can specify a custom ContentType header:
@@ -787,6 +784,20 @@ const app = createExpressServer({
787784
app.listen(3000);
788785
```
789786

787+
#### Selectively disable request/response transform
788+
789+
To disable `class-transformer` on a per-controller or per-route basis, use the `transformRequest` and `transformResponse` options on your controller and route decorators:
790+
791+
```typescript
792+
@Controller("/users", {transformRequest: false, transformResponse: false})
793+
export class UserController {
794+
795+
@Get("/", {transformResponse: true}) {
796+
// route option overrides controller option
797+
}
798+
}
799+
```
800+
790801
## Using middlewares
791802

792803
You can use any exist express / koa middleware, or create your own.
@@ -1175,7 +1186,7 @@ If its a class - then instance of this class will be created.
11751186
This technique works not only with `@Body`, but also with `@Param`, `@QueryParam`, `@BodyParam` and other decorators.
11761187
Learn more about class-transformer and how to handle more complex object constructions [here][4].
11771188
This behaviour is enabled by default.
1178-
If you want to disable it simply pass `classTransformer: false` to createExpressServer method.
1189+
If you want to disable it simply pass `classTransformer: false` to createExpressServer method. Alternatively you can disable transforming for [individual controllers or routes](#selectively-disable-requestresponse-transforming).
11791190

11801191
## Auto validating action params
11811192

src/ActionParameterHandler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export class ActionParameterHandler<T extends BaseDriver> {
162162
*/
163163
protected transformValue(value: any, paramMetadata: ParamMetadata): any {
164164
if (this.driver.useClassTransformer &&
165+
paramMetadata.actionMetadata.options.transformRequest !== false &&
165166
paramMetadata.targetType &&
166167
paramMetadata.targetType !== Object &&
167168
!(value instanceof paramMetadata.targetType)) {
@@ -197,4 +198,4 @@ export class ActionParameterHandler<T extends BaseDriver> {
197198
return value;
198199
}
199200

200-
}
201+
}

src/RoutingControllersOptions.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ export interface RoutingControllersOptions {
4040
*/
4141
classTransformer?: boolean;
4242

43-
/**
44-
* Toggles class-transformer serialization for response values.
45-
* Overwritten by a negative classTransformer value.
46-
*/
47-
useResponseClassTransformer?: boolean;
48-
4943
/**
5044
* Global class transformer options passed to class-transformer during classToPlain operation.
5145
* This operation is being executed when server returns response to user.

src/TransformationOptions.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Options for toggling class-transformer serialization.
3+
*/
4+
export interface TransformationOptions {
5+
/**
6+
* If set to false, class-transformer won't be used to perform request serialization.
7+
*/
8+
transformRequest?: boolean;
9+
10+
/**
11+
* If set to false, class-transformer won't be used to perform response serialization.
12+
*/
13+
transformResponse?: boolean;
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {TransformationOptions} from "../TransformationOptions";
2+
3+
/**
4+
* Extra options that apply to each controller action.
5+
*/
6+
export interface ControllerOptions extends TransformationOptions {
7+
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {TransformationOptions} from "../TransformationOptions";
2+
3+
/**
4+
* Extra handler-specific options.
5+
*/
6+
export interface HandlerOptions extends TransformationOptions {
7+
8+
}

src/decorator/Controller.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import {getMetadataArgsStorage} from "../index";
2+
import {ControllerOptions} from "../decorator-options/ControllerOptions";
23

34
/**
45
* Defines a class as a controller.
56
* Each decorated controller method is served as a controller action.
67
* Controller actions are executed when request come.
78
*
89
* @param baseRoute Extra path you can apply as a base route to all controller actions
10+
* @param options Extra options that apply to all controller actions
911
*/
10-
export function Controller(baseRoute?: string): Function {
12+
export function Controller(baseRoute?: string, options?: ControllerOptions): Function {
1113
return function (object: Function) {
1214
getMetadataArgsStorage().controllers.push({
1315
type: "default",
1416
target: object,
15-
route: baseRoute
17+
route: baseRoute,
18+
options
1619
});
1720
};
18-
}
21+
}

src/decorator/Delete.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1+
import {HandlerOptions} from "../decorator-options/HandlerOptions";
12
import {getMetadataArgsStorage} from "../index";
23

34
/**
45
* Registers a controller method to be executed when DELETE request comes on a given route.
56
* Must be applied on a controller action.
67
*/
7-
export function Delete(route?: RegExp): Function;
8+
export function Delete(route?: RegExp, options?: HandlerOptions): Function;
89

910
/**
1011
* Registers a controller method to be executed when DELETE request comes on a given route.
1112
* Must be applied on a controller action.
1213
*/
13-
export function Delete(route?: string): Function;
14+
export function Delete(route?: string, options?: HandlerOptions): Function;
1415

1516
/**
1617
* Registers a controller method to be executed when DELETE request comes on a given route.
1718
* Must be applied on a controller action.
1819
*/
19-
export function Delete(route?: string|RegExp): Function {
20+
export function Delete(route?: string|RegExp, options?: HandlerOptions): Function {
2021
return function (object: Object, methodName: string) {
2122
getMetadataArgsStorage().actions.push({
2223
type: "delete",
2324
target: object.constructor,
2425
method: methodName,
25-
route: route
26+
route: route,
27+
options
2628
});
2729
};
2830
}

src/decorator/Get.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1+
import {HandlerOptions} from "../decorator-options/HandlerOptions";
12
import {getMetadataArgsStorage} from "../index";
23

34
/**
45
* Registers an action to be executed when GET request comes on a given route.
56
* Must be applied on a controller action.
67
*/
7-
export function Get(route?: RegExp): Function;
8+
export function Get(route?: RegExp, options?: HandlerOptions): Function;
89

910
/**
1011
* Registers an action to be executed when GET request comes on a given route.
1112
* Must be applied on a controller action.
1213
*/
13-
export function Get(route?: string): Function;
14+
export function Get(route?: string, options?: HandlerOptions): Function;
1415

1516
/**
1617
* Registers an action to be executed when GET request comes on a given route.
1718
* Must be applied on a controller action.
1819
*/
19-
export function Get(route?: string|RegExp): Function {
20+
export function Get(route?: string|RegExp, options?: HandlerOptions): Function {
2021
return function (object: Object, methodName: string) {
2122
getMetadataArgsStorage().actions.push({
2223
type: "get",
2324
target: object.constructor,
2425
method: methodName,
25-
route: route
26+
options,
27+
route
2628
});
2729
};
28-
}
30+
}

src/decorator/Head.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1+
import {HandlerOptions} from "../decorator-options/HandlerOptions";
12
import {getMetadataArgsStorage} from "../index";
23

34
/**
45
* Registers an action to be executed when HEAD request comes on a given route.
56
* Must be applied on a controller action.
67
*/
7-
export function Head(route?: RegExp): Function;
8+
export function Head(route?: RegExp, options?: HandlerOptions): Function;
89

910
/**
1011
* Registers an action to be executed when HEAD request comes on a given route.
1112
* Must be applied on a controller action.
1213
*/
13-
export function Head(route?: string): Function;
14+
export function Head(route?: string, options?: HandlerOptions): Function;
1415

1516
/**
1617
* Registers an action to be executed when HEAD request comes on a given route.
1718
* Must be applied on a controller action.
1819
*/
19-
export function Head(route?: string|RegExp): Function {
20+
export function Head(route?: string|RegExp, options?: HandlerOptions): Function {
2021
return function (object: Object, methodName: string) {
2122
getMetadataArgsStorage().actions.push({
2223
type: "head",
2324
target: object.constructor,
2425
method: methodName,
25-
route: route
26+
options,
27+
route
2628
});
2729
};
28-
}
30+
}

0 commit comments

Comments
 (0)