Reputation: 1080
I am trying to upload a file using builtin multer and after then sending the response back to the user for success or failure. It was all going good until today, when I try to upload the Response wont come. after digging a bit I find out that when i use @res with @UploadedFile it does not execute the controller. I am new to nest.js.
Working.
@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar) {
console.log(req.body);
if (!req.body.user_id) {
throw new Error('id params not found.');
}
try {
const resultUpload = await this.userService.uploadUserImage(
req.body.user_id,
avatar,
); // returns the url for the uploaded image
return resultUpload;
} catch (error) {
console.log(error);
return error;
}
}
Not Working.
@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar, @Res() res) {
console.log(req.body);
if (!req.body.user_id) {
throw new Error('id params not found.');
}
try {
const resultUpload = await this.userService.uploadUserImage(
req.body.user_id,
avatar,
); // returns the url for the uploaded image
return resultUpload;
res.send(resultUpload);
} catch (error) {
console.log(error);
res.send(error);
}
}
Upvotes: 4
Views: 1328
Reputation: 5141
look, when you are using an interceptor, you are handling (with using .handle()
) the stream of response (observable
) not a whole package of it, but using express @Res
actually is somehow getting around the whole flow of response streaming.
this is also explicitly mentioned in nestjs official documents:
We already know that handle() returns an Observable. The stream contains the value returned from the route handler, and thus we can easily mutate it using RxJS's map() operator.
WARNING
The response mapping feature doesn't work with the library-specific response strategy (using the @Res() object directly is forbidden).
Upvotes: 0
Reputation: 60357
In nest, you should always avoid injecting @Res
because then you lose a lot of things that make nest so great: interceptors, exception filters,...
And actually, in most cases you don't need @Res
since nest will automatically handle sending the response correctly.
If you want to send data from a controller method, you can just return the data (Promises
and Observables
will be resolved automatically as well). If you want to send an error to the client, you can just throw the corresponding HttpException
, e.g. 404 -> NotFoundException
:
@Post('uploads/avatar')
async uploadFile(@Req() req, @UploadedFile() avatar) {
if (!req.body.user_id) {
// throw a 400
throw new BadRequestException('id params not found.');
}
try {
const resultUpload = await this.userService.uploadUserImage(
req.body.user_id,
avatar,
);
return resultUpload;
} catch (error) {
if (error.code === 'image_already_exists') {
// throw a 409
throw new ConflictException('image has already been uploaded');
} else {
// throw a 500
throw new InternalServerException();
}
}
}
If for some reason you have to inject @Res
here, you cannot use the FilesInterceptor
. Then you have to configure the multer
middleware yourself.
You can create a custom decorator for accessing the userId
:
import { createParamDecorator } from '@nestjs/common';
export const UserId = createParamDecorator((data, req) => {
if (!req.body || !req.body.user_id) {
throw new BadRequestException('No user id given.')
}
return req.body.user_id;
});
and then use it in your controller method like this:
@Post('uploads/avatar')
async uploadFile(@UserId() userId, @UploadedFile() avatar) {
Upvotes: 1