Skip to content

Instantly share code, notes, and snippets.

@LuckyArdhika
Last active February 19, 2023 01:32
Show Gist options
  • Save LuckyArdhika/a9ecf80486e97a4c57b7fe9a35b8214c to your computer and use it in GitHub Desktop.
Save LuckyArdhika/a9ecf80486e97a4c57b7fe9a35b8214c to your computer and use it in GitHub Desktop.
Files Filtering In Nestjs With Decorator or DTO
// Void Decorator, File Filter
import { createParamDecorator, ExecutionContext, BadRequestException, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
// First Choice
export const FileLimiter = createParamDecorator((data: { maxSize: number, mimeType: string[] }, req) => {
const files = req.files;
const invalidFiles = [];
for (const file of files) {
if (file.size > data.maxSize) {
invalidFiles.push({ name: file.originalname, error: 'File size exceeds maximum limit.' });
} else if (!data.mimeType.includes(file.mimetype.split('/')[1])) {
invalidFiles.push({ name: file.originalname, error: 'Invalid file type.' });
}
}
if (invalidFiles.length > 0) {
throw new BadRequestException(invalidFiles);
}
});
// Second choice (priority)
export const FilesFilter = (data: { maxSize: number, type: string[], count: number }) => {
return (target: object, key: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function(...args) {
const files = args[0] ?? args[1];
if (!files || !Array.isArray(files)) throw new BadRequestException('No files were uploaded');
const invalidFiles = [];
if (files.length > count) throw new BadRequestException(`Number of files must be less than or equal to ${count}`);
for (const file of files) {
if (file.size > data.maxSize) {
invalidFiles.push({ name: file.originalname, error: 'File size exceeds maximum limit.' });
} else if (!data.type.includes(file.mimetype.split('/')[1])) {
invalidFiles.push({ name: file.originalname, error: 'Invalid file type.' });
}
}
if (invalidFiles.length > 0) {
throw new BadRequestException(invalidFiles);
}
request.files = files;
return originalMethod.apply(this, args);
};
UseInterceptors(FileInterceptor('files'))
return descriptor;
};
};
// Usage // maxFiles: 10, maxSize/file: 1Mb, mimeType: contains
@FilesFilter({count: 10, maxSize: 100000, type: ['jpg','png','pdf']})
@Post('/uploads')
// ##########################################################################################################################
*Or using DTO*
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsOptional, IsNumber, Max, Min, Matches } from 'class-validator';
// Single File
export class FileUploadDto {
@ApiProperty({ type: 'string', format: 'binary' })
@IsString()
@IsOptional()
file: any;
@ApiPropertyOptional()
@IsString()
@IsOptional()
filename?: string;
@ApiPropertyOptional()
@IsNumber()
@IsOptional()
@Min(1)
@Max(10 * 1024 * 1024) // 10MB in bytes
size?: number;
@ApiPropertyOptional()
@IsString()
@IsOptional()
@Matches(/image\/(jpeg|png)/, {
message: 'Only JPG and PNG files are allowed',
})
mimetype?: string;
}
// Files
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsOptional, IsNumber, Max, Min, Matches } from 'class-validator';
export class FileUploadDto {
@ApiProperty({ type: 'array', items: { type: 'string', format: 'binary' } })
@IsString({ each: true })
@IsOptional()
files: any[];
@ApiPropertyOptional()
@IsString()
@IsOptional()
filename?: string[];
@ApiPropertyOptional()
@IsNumber({}, { each: true })
@IsOptional()
@Min(1)
@Max(10 * 1024 * 1024) // 10MB in bytes
size?: number[];
@ApiPropertyOptional()
@IsString({ each: true })
@IsOptional()
@Matches(/image\/(jpeg|png)/, {
each: true,
message: 'Only JPG and PNG files are allowed',
})
mimetype?: string[];
}
// Controller (Ussing DTO)
@Post()
@ApiConsumes('multipart/form-data')
async uploadFiles(@UploadedFiles() files: Express.Multer.File[], fileUploadDto: FileUploadDto) {
await this.fileUploadService.validateFileUploadDto(fileUploadDto);
// Process the uploaded files
// ...
}
// Service
export class FileUploadService {
async validateFileUploadDto(fileUploadDto: FileUploadDto) {
const errors = await validate(fileUploadDto);
if (errors.length > 0) {
throw new BadRequestException(errors);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment