Skip to content

Instantly share code, notes, and snippets.

@jonilsonds9
Last active October 17, 2023 23:11
Show Gist options
  • Save jonilsonds9/efc228e34a298fa461d378f48ef67836 to your computer and use it in GitHub Desktop.
Save jonilsonds9/efc228e34a298fa461d378f48ef67836 to your computer and use it in GitHub Desktop.
Uploading binary file (buffer) using NestJS
// 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.
@UncleFirefox
Copy link

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/

@MegaSpaceHamlet
Copy link

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