typestack / routing-controllers

Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage in Express / Koa using TypeScript and Routing Controllers Framework.
MIT License
4.41k stars 394 forks source link

question: how to auto-transform body instance to plain in routing-controllers #1133

Open ermal-abiti opened 1 year ago

ermal-abiti commented 1 year ago

I have this following code:

@JsonController('/auth')
@Service()
export class AuthController {
    constructor(private readonly authService: AuthService) {}

    @Post('/register')
    @HttpCode(201)
    @Serialize(UserDto)
    async registerUser (@Body() body: RegisterDto) {
        console.log(body)
        return this.authService.register(body.toJson());
    }
}

As you can see the controller is using validation. After I call the api endpoint, the console outputs RegisterDto { username: 'test', password: 'test' }.

Coming from a nestjs perspective, it would automatically convert this dto instance to a plain object, and the console would output this { username: 'ermal1', password: 'dasd' }.

How can i achieve this using routing-controllers ?

attilaorosz commented 1 year ago

@ermal-abiti you can disable class transformation in either the global settings of routing-controller or per parameter basis. Please take a look at the documentation and search for class-transformer

ermal-abiti commented 1 year ago

@attilaorosz attilaorosz I disabled:

useExpressServer(app, {
    routePrefix: '/api',
    validation: {
        whitelist: true,
    },
    controllers: [AuthController],
    defaultErrorHandler: true,
    classTransformer: false,
});

But now it is not validating the body and it is not applying the whitelist: true at validation options.

DTO:

export class RegisterDto {
    @IsString()
    username: string;

    @IsString()
    password: string;
}

And I am sending this json request body:

{
 "username":"test",
"password:"test"
"name": "test"
}

And the console is outputing this: { username: 'test', password: 'test', name: 'test' }

Also if i remove one of the fields and i send this json for ex: {"username": "test"}, it skips the validation part, so it doesn't throw an error or something. Shouldn't it validate based on the DTO ?

ermal-abiti commented 1 year ago

Any solution for this ?

attilaorosz commented 1 year ago

Sorry for the late reply, do you happen to have a repro repo for this? I have no idea what @Serialize() does in your example.

ermal-abiti commented 1 year ago

@attilaorosz @Serialize() does not have to do with this. I have

// index.js
...
useExpressServer(app, {
    routePrefix: '/api',
    validation: {
        whitelist: true,
    },
    controllers: [AuthController],
    defaultErrorHandler: true,
    classTransformer: true,
});
...
// auth.controller.ts
@JsonController('/auth')
@Service()
export class AuthController {
    constructor(private readonly authService: AuthService) {}

    @Post('/register')
    @HttpCode(201)
    async registerUser (@Body() body: RegisterDto) {
        console.log(body)
        return this.authService.register(body);
    }
}

The problem is at body in /register route. I want body to a be plain object after validation, for example { username: 'test', password: 'test' }. But by default body after validation comes as RegisterDto { username: 'test', password: 'test' } (instance of RegisterDto). Otherwise if I set classTransformer: false, the body comes as plain object but it does not go through the validation process. What i want to achieve is validate the body and return it after validation as plain object { username: 'ermal1', password: 'dasd' }. Is there any specific option for this ? Thanks for your response