Last active
October 17, 2023 23:11
-
-
Save jonilsonds9/efc228e34a298fa461d378f48ef67836 to your computer and use it in GitHub Desktop.
Uploading binary file (buffer) using NestJS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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. |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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 theBody
of the request mark the type asbinary
and then use theSelect 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 theBody
of the request selectBinary File
and in the field SELECTED FILE click and select the file you want to upload and then test, see the image: