Myles
Myles

Reputation: 484

set request body size limit on NestJs for single controller

I want to increase request body size limit for a single route, let's say only for route /uploads, and keep the rest to be the default.

I know you can set globally using

app.use(json({ limit: '50mb' }));

Or, when in pure ExpressJS you can use

router.use('/uploads', express.json({ limit: '50MB' }));

But in NestJS there's only a global app and controller classes. E.g.

@Controller('uploads')
export class UploadController {
  constructor() {}

  @Post()
  create(...): Promise<any> {
    ...
  }
}

Where to set the limit for this controller?

Upvotes: 4

Views: 14846

Answers (3)

binici
binici

Reputation: 915

Instead of setting the size limit per route in main.ts, you can set a high limit for all routes and then use an interceptor to set a limit per controller. And the client will get a more descriptive error when exceeding the limit.

import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class SizeLimitInterceptor implements NestInterceptor {
    private sizeLimit = 0;

    constructor(sizeLimit: number) {
        this.sizeLimit = sizeLimit;
    }

    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const ctx = context.switchToHttp();
        const request = ctx.getRequest();
        const response = ctx.getResponse();
        const size = request.socket.bytesRead;

        if (size > this.sizeLimit) {
            throw new HttpException('Request Entity Too Large Error', 413);
        }

        return next.handle();
    }
}

And you can use this interceptor like this in your controller:

@UseInterceptors(new SizeLimitInterceptor(1024 * 1024 * 10))

Upvotes: 2

binici
binici

Reputation: 915

Actually, it is possible to increase the size limit for one route in NestJS, like this:

     app.use('/uploads', json({ limit: '50mb' }));
     app.use(json({ limit: '100kb' }));

Second statement is needed for resetting the limit for all other routes.

Upvotes: 11

pismenskiy
pismenskiy

Reputation: 31

You can use guard for this.

import {
  Injectable,
  CanActivate,
  ExecutionContext,
  applyDecorators,
  UseGuards,
  SetMetadata,
} from '@nestjs/common'
import { Reflector } from '@nestjs/core'

@Injectable()
export class LimitGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest()
    const limit = this.reflector.get<string[]>('limit', context.getHandler())
    return limit > request.socket.bytesRead
  }
}

export const Limit = (limit: number) =>
  applyDecorators(UseGuards(LimitGuard), SetMetadata('limit', limit))

and, in your controller

  @Limit(1024 * 1024)
  @Post('your-path')
  async limitedMethod(): Promise<string> {
    // ...
  }

Upvotes: 3

Related Questions