Nestjs file upload like a Pro [in depth]
![Nestjs file upload like a Pro [in depth]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1725696291283%2F25744130-64a6-436a-9153-33c4845e0c17.jpeg&w=3840&q=75)
Search for a command to run...
![Nestjs file upload like a Pro [in depth]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1725696291283%2F25744130-64a6-436a-9153-33c4845e0c17.jpeg&w=3840&q=75)
No comments yet. Be the first to comment.
Awesome JavaScript Interviews https://www.youtube.com/embed/YSteqFk_Z5k?si=R-49qQPQ7ml0jngz Table of Contents of this Readme file Most common Fundamental JavaScript Interview Topics & Questions Most common Tricky Javascript Interview Topics & Quest...

Table of Contents (Top Questions) This list contains the top essential questions that are frequently-asked during Front End Engineer interviews. Concise versions of the answers are presented here with links to elaborate versions for further reading. ...
Table of Contents No.Questions 1What are the possible ways to create objects in JavaScript 2What is a prototype chain 3What is the difference between Call, Apply and Bind 4What is JSON and its common operations 5What is the purpose of the...
1. Event-Driven Programming Paradigm in Node.js Node.js follows an event-driven programming paradigm where actions are triggered by events. The core of Node.js, known as the event loop, continuously listens for events and executes associated callback...

1. What is middleware in the context of Express.js? How is it used? Middleware in Express.js refers to functions that have access to the request, response, and the next middleware function in the application’s request-response cycle. It is used to pe...

Introduction
File uploads are a common feature in many web applications. NestJS, a progressive Node.js framework, provides a convenient way to handle file uploads and integrate with cloud storage services like AWS S3. In this blog post, we'll explore how to implement file uploads with validation in NestJS and store the uploaded files on AWS S3. sample example i am showing here --
Prerequisites
Steps:
Install Required Packages:
npm install @nestjs/platform-express @nestjs/aws-sdk/s3 multer
Create an S3 Service:
import { Injectable } from '@nestjs/common';
import { S3 } from '@nestjs/aws-sdk/s3';
@Injectable()
export class S3Service {
constructor(private readonly s3: S3) {}
async uploadFile(file: Express.Multer.File): Promise<string> {
const params = {
Bucket: 'your-bucket-name',
Key: file.originalname,
Body: file.buffer,
ContentType: file.mimetype,
};
const result = await this.s3.upload(params).promise();
return result.Location;
}
}
Configure Multer:
import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
@Module({
imports: [
MulterModule.register({
storage: multer.diskStorage({
destination: './uploads',
filename: (req, file, cb) => {
cb(null, `${file.originalname}-${Date.now()}`);
},
}),
}),
],
})
export class UploadModule {}
Create a Controller:
import { Controller, Post, UseInterceptors, UploadedFile, UploadedFiles } from '@nestjs/common';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import { S3Service } from './s3.service';
@Controller('upload')
export class UploadController {
constructor(private readonly s3Service: S3Service) {}
@Post('single')
@UseInterceptors(FileInterceptor('file'))
async uploadSingleFile(@UploadedFile() file: Express.Multer.File) {
const url = await this.s3Service.uploadFile(file);
return { url };
}
@Post('multiple')
@UseInterceptors(FilesInterceptor('files'))
async uploadMultipleFiles(@UploadedFiles() files: Express.Multer.File[]) {
const urls = await Promise.all(files.map(file => this.s3Service.uploadFile(file)));
return { urls };
}
}
Code example with Validation
// Native.
/* eslint-disable no-useless-escape */
// Package.
import {
Body,
Controller,
Get,
HttpCode,
HttpStatus,
UploadedFile,
UseInterceptors,
ParseFilePipeBuilder,
Param,
Post,
Query,
UseGuards,
UsePipes,
ValidationPipe,
Req,
BadRequestException,
UploadedFiles,
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiConsumes,
ApiCreatedResponse,
ApiForbiddenResponse,
ApiInternalServerErrorResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiTags,
ApiUnprocessableEntityResponse,
} from '@nestjs/swagger';
import { INTERNAL_SERVER_ERROR, NO_ENTITY_FOUND } from '../../../app.constants';
import { RestaurantService } from '../services/restaurant.service';
import { Type } from 'class-transformer';
import {
CreateRestaurantBodyDto,
SearchQueryDto,
getRestaurantByIdDto,
} from '../dto/restaurant.dto';
import { RolesAllowed } from '../../../core/decorator/role.decorator';
import { Roles } from '../../../core/roles';
import { RolesGuard } from '../../../core/guard/role.guard';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import {
uploadFile,
uploadFiles,
} from '../../../core/decorator/file.decorator';
import { imageFileFilter } from '../../../core/filters/file.filter';
import { GetCurrentUser, User, UserData, UserMetaData } from '../interface';
const SIZE = 2 * 1024 * 1024;
const VALID_UPLOADS_MIME_TYPES = ['image/jpeg', 'image/png'];
@ApiBearerAuth('authorization')
@Controller('restaurants')
@UseGuards(RolesGuard)
@UsePipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
)
@ApiTags('restaurant')
export class RestaurantController {
constructor(private readonly service: RestaurantService) {}
// multiple file upload
@UseGuards(RolesGuard)
// add all roles which we want to allow
@RolesAllowed(Roles['admin'])
@HttpCode(HttpStatus.OK)
@ApiConsumes('application/json')
@ApiNotFoundResponse({ description: NO_ENTITY_FOUND })
@ApiForbiddenResponse({ description: 'UNAUTHORIZED_REQUEST' })
@ApiUnprocessableEntityResponse({ description: 'BAD_REQUEST' })
@ApiInternalServerErrorResponse({ description: INTERNAL_SERVER_ERROR })
@ApiOperation({
description: 'search restaurants based on lat/lon',
})
@ApiOkResponse({
description: 'return search restaurants successfully',
})
@Get('/:id')
public async getRestaurantById(@Param() param: getRestaurantByIdDto) {
return await this.service.getRestaurantById(param);
}
// multiple file upload
@UseGuards(RolesGuard)
// add all roles which we want to allow
@RolesAllowed(Roles['admin'])
// one file upload
@Post('one-file')
// custom decorator
// ONE FILE UPLOAD ONLY
@uploadFile('file')
@ApiForbiddenResponse({ description: 'UNAUTHORIZED_REQUEST' })
@ApiUnprocessableEntityResponse({ description: 'BAD_REQUEST' })
@ApiInternalServerErrorResponse({ description: INTERNAL_SERVER_ERROR })
@UseInterceptors(FileInterceptor('file'))
@ApiConsumes('multipart/form-data')
public async uploadFileOne(
@UploadedFile(
new ParseFilePipeBuilder()
.addFileTypeValidator({ fileType: /(jpg|png)$/ })
.addMaxSizeValidator({ maxSize: SIZE })
.build({
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
}),
)
file: Express.Multer.File,
) {
try {
return file;
} catch (err) {
throw err;
}
}
// multiple file upload
@UseGuards(RolesGuard)
// add all roles which we want to allow
// upload many files together P
@RolesAllowed(Roles['admin'])
@Post('many-files')
// custom decorator
@uploadFiles('file')
@ApiForbiddenResponse({ description: 'UNAUTHORIZED_REQUEST' })
@ApiUnprocessableEntityResponse({ description: 'BAD_REQUEST' })
@ApiInternalServerErrorResponse({ description: INTERNAL_SERVER_ERROR })
@UseInterceptors(FilesInterceptor('file'))
// all plural here
// validation with many files
@ApiConsumes('multipart/form-data')
public async uploadFiles(
@UploadedFiles(
// it will validate each and every files
new ParseFilePipeBuilder()
.addFileTypeValidator({ fileType: /(jpg|png)$/ })
.addMaxSizeValidator({ maxSize: SIZE })
.build({
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
}),
)
files: Array<Express.Multer.File>,
) {
try {
// once we have files lets upload them in a Loop
console.log(files);
return await this.service.upload(files);
} catch (err) {
throw err;
}
}
// multiple file upload
@UseGuards(RolesGuard)
// add all roles which we want to allow
@RolesAllowed(Roles['admin'])
@Post('custom-validation')
// custom decorator
@uploadFile('file')
@ApiForbiddenResponse({ description: 'UNAUTHORIZED_REQUEST' })
@ApiUnprocessableEntityResponse({ description: 'BAD_REQUEST' })
@ApiInternalServerErrorResponse({ description: INTERNAL_SERVER_ERROR })
@UseInterceptors(
FileInterceptor('file', {
fileFilter: imageFileFilter,
}),
)
@ApiConsumes('multipart/form-data')
public async uploadFilev2(@Req() req: any, @UploadedFile() file) {
console.log(file);
if (!file || req.fileValidationError) {
throw new BadRequestException(
'invalid file provided, allowed *.pdf single file for Invoice',
);
}
return file;
}
}
class-validator to validate uploaded files.Additional Considerations:
By following these steps and incorporating validation, you can effectively handle file uploads in your NestJS applications and store them securely on AWS S3.
Part-1 %[https://www.youtube.com/watch?v=hsKYAVImMgg ]
Part-2 %[https://www.youtube.com/watch?v=0_bMzkvgIoc]
Playlist %[https://www.youtube.com/watch?v=GSoGVlG1MTQ&list=PLIGDNOJWiL1-8hpXEDlD1UrphjmZ9aMT1]
Github https://github.com/tkssharma/nestjs-advanced-2023/tree/main/apps/22-nestjs-file-upload