[ AWS ] AWS S3 버킷에 NestJS로 이미지 업로드하기 2편. NestJS로 업로드 하기
in BackEnd
전단계가 궁금하신 분들은 1편) https://soraji.github.io/back/2023/02/14/awsS3/ 를 보고 오시길!
이미지를 올리려면 AWS S3와 연결할 수 있는 라이브러리를 설치해야한다.
$ yarn add multer aws-sdk multer-s3 @aws-sdk/client-s3
그리고 컨트롤러에서는
import { Controller, Post, Req, Res, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ImageMainLectureService } from './imageMainLecture.service';
@Controller('imageMainLecture')
@UseGuards(AuthGuard('teacher'))
export class ImageMainLectureController {
constructor(
private readonly imageMainLectureService: ImageMainLectureService
) {}
async create(@Req() request, @Res() response) {
try {
await this.imageMainLectureService.fileupload(request, response);
} catch (error) {
return response
.status(500)
.json(`Failed to upload image file: ${error.message}`);
}
}
}
이렇게 클래스를 만들고
await this.imageMainLectureService.fileupload(request, response);
service로 비즈니스 로직을 넘겨준다
서비스단에서는
import { Req, Res, Injectable } from '@nestjs/common';
import * as multer from 'multer';
import * as AWS from 'aws-sdk';
import * as multerS3 from 'multer-s3';
import { S3Client } from '@aws-sdk/client-s3';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ImageMainLecture } from './entities/imageMainLecture.entity';
AWS.config.update({
accessKeyId: process.env.AWS_BUCKET_ACCESS_KEY,
secretAccessKey: process.env.AWS_BUCKET_SECRET_KEY
});
@Injectable()
export class ImageMainLectureService {
async fileupload(@Req() req, @Res() res) {
const result = this.upload(req, res, async function (error) {
if (error) {
console.log(error);
return res
.status(404)
.json(`이미지 업로드에 실패했습니다: ${error}`);
}
res.status(201).json(req.files[0].location);
});
}
upload = multer({
storage: multerS3({
s3: new S3Client({
credentials: {
accessKeyId: process.env.AWS_BUCKET_ACCESS_KEY as string,
secretAccessKey: process.env.AWS_BUCKET_SECRET_KEY as string
},
region: 'ap-northeast-2'
}),
contentType: multerS3.AUTO_CONTENT_TYPE,
bucket: process.env.AWS_BUCKET_NAME,
acl: 'public-read',
key: function (request, file, cb) {
cb(null, `image/main/${Date.now().toString()}-${file.originalname}`);
}
})
}).array('upload', 1);
}
이렇게 작성해준다.
res.status(201).json(req.files[0].location);
aws에 저장되는 url은 location으로 넘어온다.
s3: new S3Client({
타입스크립트가 아니면 s3 : s3 이렇게 하던데.. 나는 타입스크립트라 credential도 작성해줘야했음.
본인이 s3를 만든 저장소의 버킷이름과 엑세스키, 시크릿키를 env파일에 넣어놓고 연결하면 된다.
contentType: multerS3.AUTO_CONTENT_TYPE,
contentType을 넣지 않으면 이미지가 url로 뜨는게 아니라 자동으로 다운로드가 되어진다. 만약에 다운로드를 원하면.. contentType을 빼주기
(그치만 그럴일이 별로 없을듯)
cb(null, `image/main/${Date.now().toString()}-${file.originalname}`);
똑같은 이름의 파일들이 업로드될 수 있기때문에 시간을 앞에 붙여서 중복이름이 없게 한다.
}).array('upload', 1);
이미지의 갯수를 정할 수 있다. 배열로 넘어가기때문에 10으로 해주면 10장이 한거번에 저장됨
이 S3로 이미지를 업로드하는건 단지 AWS에 업로드 하는 것만 해당하는 내용이다.
디비에 저장되는건 여기서 처리해야하는 로직이 아님
나도 처음에는 service단에다가 DI로 레포를 만들어서 save를 했는데,
생각해보니까 그렇게 하면 안됐다 (매번 헷갈림 σ(´し_`〃)ゞ)
이 컨트롤러에서는 단지 aws에 저장하고, 해당하는 url만 리턴시켜주면 된다.
예를 들어 유저의 프로필 사진을 등록한다고 치면, 그 url을 가지고 db에 저장하는건 유저를 등록할때 해야하는 작업이지, 이미지를 등록할때 db에 저장하는게 아닌것이다.
그러니까 이미지등록 폴더에는 dto도, entity도 존재하지 않는다.
댓글은 힘과 사랑이에요 (●’ᴗ’●)ノ♥