multipart-form 데이터
미디어 파일을 보낼 때는 어떻게 해야하는가.
content-type 이라고
데이터를 보낼 때 헤더에 설정하는 부분이 있다.
여기를 multipart-form 데이터로 설정해야 한다.
multer 패키지 설치
npm i -D @types/multer
단일 파일을 사용하기 위해서는..
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
console.log(file);
}
위와 같은 인터셉터를 사용하라고 되어있음.
@ApiOperation({ summary: '이미지 업로드' })
@Post('upload')
@UseInterceptors(FileInterceptor('files'))
uploadCatImg(@UploadedFiles() files: Array<Express.Multer.File>) {
console.log(files);
return 'uploadImg';
}
위와 같이 사용하면 file들의 배열 형태로 받을 수 있게 된다.
또한 Module에 import 시켜줘야 한다.
MulterModule.register({dest: './upload'}),
dest 는 destination 목적지 url 을 입력해줌.
upload 해보면…
{success: true, data: "uploadImg"}
위와 같이 뜨는 것을 확인할 수 있다.
그러면 서버 폴더의 upload 폴더 안에 이미지가 들어가는 것을 확인할 수 있다.

multer options
import * as multer from 'multer';
import * as path from 'path';
import * as fs from 'fs';
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';
const createFolder = (folder: string) => {
try {
console.log('💾 Create a root uploads folder...');
fs.mkdirSync(path.join(__dirname, '..', `uploads`));
} catch (error) {
console.log('The folder already exists...');
}
try {
console.log(`💾 Create a ${folder} uploads folder...`);
fs.mkdirSync(path.join(__dirname, '..', `uploads/${folder}`));
} catch (error) {
console.log(`The ${folder} folder already exists...`);
}
};
const storage = (folder: string): multer.StorageEngine => {
createFolder(folder);
return multer.diskStorage({
destination(req, file, cb) {
//* 어디에 저장할 지
const folderName = path.join(__dirname, '..', `uploads/${folder}`);
cb(null, folderName);
},
filename(req, file, cb) {
//* 어떤 이름으로 올릴 지
const ext = path.extname(file.originalname);
const fileName = `${path.basename(
file.originalname,
ext,
)}${Date.now()}${ext}`;
cb(null, fileName);
},
});
};
export const multerOptions = (folder: string) => {
const result: MulterOptions = {
storage: storage(folder),
};
return result;
};
위 코드를 common/utils/multer.options.ts 안에 넣어둔다.
폴더 만들어주고, 파일 명 만들어주는 로직임.
@UseInterceptors(FilesInterceptor('image', 10, multerOptions("cats")))
최대 10개까지 된다.
일단 이미지가 서버 프로그램 경로에 들어가는 것을 확인할 수 있다.
MiddleWare를 만들어주기
데이터베이스에는 파일의 경로명이 들어가있어야 한다.
그 경로명을 넣어주기 위해 Middleware를 만들어준다.
먼저 main.ts 에서
app.useStaticAssets(path.join(__dirname, './common', 'uploads'), {
prefix: '/media',
});
여기에서 useStaticAssets 가 없다고 에러가 뜰 것이다.
얘는 express application이라고 명시해줘야한다.
const app = await NestFactory.create<NestExpressApplication>(AppModule);
위의 prefix: ‘media’ 에 대하여…
이렇게 함으로써, // http://localhost:8000/media/cats/aaa.png 에 접근하여 해당 파일을 가져올 수 있게 해주는 것이다.
이제 마지막으로
controller 에서
@ApiOperation({ summary: '이미지 업로드' })
@Post('upload')
@UseInterceptors(FilesInterceptor('image', 10, multerOptions("cats")))
uploadCatImg(@UploadedFiles() files: Array<Express.Multer.File>) {
console.log(files);
// return 'uploadImg';
return { images: `http://localhost:8000/media/cats/${files[0].filename}` };
}
일단 0번째 인덱스에 있는 filename 을 기반으로 저장시켜준다.
스키마에 default 사진 가져오도록 수정
@Prop({
default:
'https://raw.githubusercontent.com/amamov/teaching-nestjs-a-to-z/main/images/1.jpeg',
})
@IsString()
imgUrl: string;
그리고, readonlydata에 imgURL 추가
readonly readOnlyData: {
id: string;
email: string;
name: string;
imgUrl: string;
};
CatSchema.virtual('readOnlyData').get(function (this: Cat) {
return {
id: this.id,
email: this.email,
name: this.name,
imgUrl: this.imgUrl,
};
});
service에 있는 메서드 가져올 것이다.
@ApiOperation({ summary: '이미지 업로드' })
@UseInterceptors(FilesInterceptor('image', 10, multerOptions("cats")))
@UseGuards(JwtAuthGuard)
@Post('upload')
uploadCatImg(@UploadedFiles() files: Array<Express.Multer.File>, @CurrentUser() cat: Cat) {
console.log(files);
// return 'uploadImg';
// return { images: `http://localhost:8000/media/cats/${files[0].filename}` };
return this.catsService.uploadImg(cat, files);
}
async uploadImg(cat: Cat, files: Express.Multer.File[]) {
const fileName = `cats/${files[0].filename}`;
console.log(fileName);
const newCat = await this.catsRepository.findByIdAndUpdateImg(
cat.id,
fileName,
);
console.log(newCat);
return newCat;
}
위와 같이 구현
이제 폴더 관리를 좀 해줘야 해서 controller를 일단 빼서 정리하였음.
보너스 POSTMAN에서 파일업로드 하기
form data 라는 애에서 file로 설정하면 파일을 올릴 수 있게 되어있음