게시물을 업로드할때, 폼데이터인 이미지 파일은 body-parser로 파싱될 수 없기 때문에 multer를 사용해야한다. 나는 multer, multer-s3, aws-sdk를 사용해서 서버의 특정 폴더(ex. uploads)를 생성해서 저장하는 형태가 아니라 s3의 버킷에 업로드하는 것으로 구현했다.
우선 multer의 storage와 limits 설정은 다음과 같이 해두었다. 이때, accessKey와 secretAccessKey 등은 자신의 AWS 계정에서 액세스 키(액세스 키 ID 및 비밀 액세스 키)
를 발급받아야 하며, aws-cli도 설치한 후 aws configure에서 액세스 키와 비밀 액세스 키를 저장해주어야한다.
//config/multer.js
const multer = require("multer");
const multerS3 = require("multer-s3");
const aws = require("aws-sdk");
require("dotenv").config();
const s3 = new aws.S3({
accessKeyId: process.env.S3_ACCESSKEYID,
secretAccessKey: process.env.S3_SECRETKEY,
region: process.env.S3_REGION,
});
const upload = multer({
storage: multerS3({
s3: s3,
bucket:
process.env.NODE_ENV !== "test"
? process.env.S3_BUCKETNAME
: process.env.S3_TESTBUCKETNAME,
acl: "public-read",
key: function (req, file, cb) {
cb(
null,
Math.floor(Math.random() * 1000).toString() +
Date.now() +
"." +
file.originalname.split(".").pop()
);
},
}),
limits: {
fileSize: 5 * 1024 * 1024,
},
});
module.exports = upload;
supertest로 게시물 업로드 api에 요청을 보내면, multer를 통해 파싱된 저장경로와 body가 ctr.createPost의 req로 전달된다.
//api/post/index.js
router.post("/", upload.single("image"), ctrl.createPost);
테스트 코드를 작성할때 폼 데이터와 바디를 전송하는데에서 한참 헤맸다. 그동안은 request(app).post("/users").send(전송할 데이터).end(done)
과 같이 send
로 데이터를 전송해주었는데, 폼 데이터를 전송할때에는 attach
를 사용한다. 여러개의 파일을 전송할 때에는 .attach를 이어서 작성해주면 된다. attach는 첫번째 인자로 input의 name에서 설정한 값을 작성하고, 두번째 인자로 파일의 경로를 작성한다.
테스트 이미지 파일을 전송하기 위해서 testImg 폴더를 생성해서 임의의 이미지 파일을 추가했고, 두번째 인자로 해당 파일의 경로를 작성했다.
ctrl.createPost에서 버킷의 경로는 req.file.location
으로 전달받고, body는 req.body.content
로 전달받는다. 그런데, 테스트 코드를 작성할때에는 attach와 send를 사용하면 두개를 동시에 쓸 수 없다는 에러가 발생한다. 따라서, 이 때에는 field로 데이터를 전송했다.
multer 설정에서 파일 사이즈를 설정해줄 수 있는데, 파일 사이즈 초과 이미지를 업로드할 경우 에러 핸들링 미들웨어로 에러를 처리할 수 있다. express 문서에 따르면, multer에서 에러가 발생할 경우 multer는 express로 에러를 넘겨준다. 따라서 if(err instance of multer.MulterError)
로 multer 에러를 처리해줄 수 있다.
나는 index.js에 작성한 에러처리 미들웨어에서 if(err.name === 'MulterError')
로 핸들링해주었다.