-
-
Save jonilsonds9/efc228e34a298fa461d378f48ef67836 to your computer and use it in GitHub Desktop.
// Had to upload a binary file but multer only works with `multipart/form-data` | |
// And NestJS parses the request. So I had to manually upload it. | |
// First in `main.ts` I had to edit the following line: | |
const app = await NestFactory.create(AppModule); | |
// For: | |
const app = await NestFactory.create(AppModule, { bodyParser: false }); | |
// So NestJS allows us to handle the request. | |
// The next step is to create a Middleware, I named it `FileBufferMiddleware` | |
// I added the following content: | |
import { Injectable, NestMiddleware } from '@nestjs/common'; | |
import { raw } from 'body-parser'; | |
@Injectable() | |
export class FileBufferMiddleware implements NestMiddleware { | |
use(req: any, res: any, next: () => void): any { | |
raw({ | |
verify: (req, res, buffer) => { | |
req['fileBuffer'] = buffer; | |
}, | |
limit: '5mb', | |
})(req, res as any, next); | |
} | |
} | |
// We need to add to our `MiddlewareModule` like so: | |
export class MiddlewareModule implements NestModule { | |
configure(consumer: MiddlewareConsumer) { | |
consumer | |
.apply(FileBufferMiddleware) | |
.forRoutes({ | |
path: '/upload/:fileName', | |
method: RequestMethod.PUT, | |
}); | |
} | |
} | |
// With that we will have a `fileBuffer` which is a Buffer object in the request. | |
// And to make it even easier, I also created a decorator named `FileBuffer`: | |
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; | |
export const FileBuffer = createParamDecorator( | |
(data: unknown, ctx: ExecutionContext) => { | |
const request = ctx.switchToHttp().getRequest(); | |
return request.fileBuffer || null; | |
}, | |
); | |
// So, we can just use the decorator in the Controller and we will already have the object ready to manipulate: | |
@Put('/upload/:fileName') | |
upload( | |
@Res() response: Response, | |
@Param() fileName: string, | |
@FileBuffer() fileBuffer, | |
): object { | |
if (fileBuffer === null) throw new BadRequestException('File is required'); | |
const writeStream = createWriteStream(`./data/${fileName}`); | |
writeStream.write(fileBuffer); | |
return response | |
.status(HttpStatus.CREATED) | |
.send({ HttpCode: 201, Message: 'File uploaded.' }); | |
} | |
// And that's it, now we have an upload using a binary file. |
Hi @emiliosanches, well I didn't quite understand the behavior you want, because the way I did it in gist, it only works for the upload route, the other routes Middleware doesn't work. Could you explain better?
@jonilsonds9 my quesstion is how to test it manually? Is there any way e.g. in Postman to test uploading file by using proposed solution?
@MastalerzKamil Yes, there's a way to test it, it's very simple, in Postman you must send a request of type Put
to the endpoint /upload/filename.png
, and then in the Body
of the request mark the type as binary
and then use the Select File
button and select the file you want to upload to the API, see the image:
Using Insomnia is even simpler, you should send a Put
request to the /upload/filename.png
endpoint, then in the Body
of the request select Binary File
and in the field SELECTED FILE click and select the file you want to upload and then test, see the image:
Just in case somebody wants to keep the old behavior for some routes, this a really cool article that walks you through: https://www.darraghoriordan.com/2021/06/20/parse-request-raw-body-nest-js-controller/
Thanks for this.
One thing to note: for me I kept on getting the BadRequestException
until I added the following line to the raw
functions options:
type: image/jpeg
Thank you! Very useful.
But, looking to the code, I think it would disable the automatic request body parsing for all requests.
Is it possible to implement this behavior only for one route and keep body-parser working normally for every other route?