AWS Lambda - API Gateway로 S3 파일 업로드 API 만들기 #1 - Lambda 함수 생성


안녕하세요. 남산돈가스입니다.

 이번 포스팅에서는 웹을 개발하면서 가장 골칫거리지만 자주 쓰이게 될 수 있는 파일 업로드 기능 구현에 대해서 포스팅하려고합니다.

 하지만 일반적인 파일업로드가 아닌, Lambda로 S3에 파일을 업로드 시키는 함수를 생성하고, 해당 Lambda함수를 API Gateway에 연결하여 multipart-form 형식으로 파일을 업로드하는 Serverless 파일업로드를 구현할 예정입니다.

 이런 방식으로 업로드기능을 구현하게 되면, 추후에 어디든지 파일업로드 기능을 쓸 수 있는 Micro Service가 될 수 있습니다.

포스팅은 다음과 같이 3회에 걸쳐 진행되겠습니다.

#1. Lambda 함수 생성

#2. API Gateway, S3 셋팅

#3. API Gateway - Lambda 연결 및 테스트


그렇다면 지금부터 그 첫번째 단계인 Lambda 함수 생성을 진행해보겠습니다.

먼저 Lambda 서비스에 접속한 뒤 Node.js 기반의 새로운 함수를 생성합니다.



함수를 생성하면 아래와 같이 트리거가 추가되지 않은 날것의 함수가 생성된 것을 확인하실 수 있습니다.
 쥐도 새도 모르게 변하는 AWS 콘솔 덕분에(?) 매번 포스팅할 때마다 Lambdad의 콘솔화면이 다채롭게  변하고있네요...ㅎㅎ



기존의 포스팅에서는 위 사진처럼 인라인으로 편집하는 포스팅만 진행했었는데 금번 포스팅에서는 외부 node_module을 사용하는 경우라 로컬에서 작업한 소스를 ZIP파일 형식으로 업로드하여 함수를 생성해보겠습니다.

로컬 터미널에서 upload라는 폴더를 생성하고 index.js을 생성합니다.

  • index.js
그리고 해당 함수에 필요한 node_module을 install 하기 위해서 npm install 명령어를 사용합니다.

필요 모듈
  • aws-sdk : AWS javascript sdk 모듈
  • parse-multipart : multipart형식으로 들어 온 파일을 데이터 형식으로 변환
  • sha1 : 암호화 모듈
  • bluebird : 비동기 Promise 패턴 매서드 사용 모듈
위의 모듈들을 npm install aws-sdk parse-multipart sha1 bluebird 명령어를 이용해 설치합니다.


gimseongsin-ui-MacBook-Pro:Desktop gimseongsin$ cd upload/
gimseongsin-ui-MacBook-Pro:upload gimseongsin$ npm install aws-sdk parse-multipart 
sha1 bluebird
/Users/gimseongsin/Desktop/upload
├─┬ aws-sdk@2.163.0
│ ├─┬ buffer@4.9.1
│ │ ├── base64-js@1.2.1
│ │ ├── ieee754@1.1.8
│ │ └── isarray@1.0.0
│ ├── crypto-browserify@1.0.9
│ ├── events@1.1.1
│ ├── jmespath@0.15.0
│ ├── querystring@0.2.0
│ ├── sax@1.2.1
│ ├─┬ url@0.10.3
│ │ └── punycode@1.3.2
│ ├── uuid@3.1.0
│ ├── xml2js@0.4.17
│ └─┬ xmlbuilder@4.2.1
│   └── lodash@4.17.4
├── bluebird@3.5.1
├── parse-multipart@1.0.4
└─┬ sha1@1.1.1
  ├── charenc@0.0.2
  └── crypt@0.0.2

npm WARN enoent ENOENT: no such file or directory, open '/Users/gimseongsin/Desktop/upload/package.json'
npm WARN upload No description
npm WARN upload No repository field.
npm WARN upload No README data
npm WARN upload No license field.

필요 모듈을 모두 설치하였다면, 앞서 생성한 index.js 에 아래와 같이 작성해줍니다.
(이후에 개인적으로 소스를 사용하신다면, 알맞게 수정하여 사용하시길 바랍니다.)

const AWS = require('aws-sdk');
const multipart = require("parse-multipart");
const s3 = new AWS.S3();
const sha1 = require('sha1');
const bluebird = require('bluebird');

exports.handler = function(event, context) {

    let result = []

    var bodyBuffer = new Buffer( event[ 'body-json' ].toString(), 'base64' );

    var boundary = multipart.getBoundary( event.params.header[ 'Content-Type' ] )

    var parts = multipart.Parse( bodyBuffer, boundary )

    let files = getFiles( parts )

    return bluebird.map( files, file => {
        console.log( `uploadCall!!!` )
        return upload( file )
        .then(
            data => {
                result.push( { data, 'file_url': file.uploadFile.full_path } )
                console.log( `data=> ${JSON.stringify( data, null, 2 )}` )
            },
            err => {
                console.log( `s3 upload err => ${err}` )
            }
        )
    })
    .then(_=> {
        return context.succeed(result)
    })
}


let upload = function( file ) {
    console.log( `putObject call!!!!` )
    return s3.upload( file.params ).promise();
};

let getFiles = function( parts ) {
    //let fileExt = 'png'
    let files = [];
    parts.forEach( part => {
        let hash = sha1( new Buffer( new Date().toString() ) );

        let buffer = part.data

        let filePath = hash + '/';

        let fileName = part.filename
        let fileFullName = filePath + fileName;

        let filefullPath = '버킷URL' + fileFullName;

        let params = {
            Bucket: '버킷명',
            Key: fileFullName,
            Body: buffer
        };

        let uploadFile = {
            size: buffer.toString( 'ascii' ).length,
            type: part.type,
            name: fileName,
            full_path: filefullPath
        };

        files.push( { params, uploadFile } )
    } );
    return files
}

index.js에 모든 소스를 작성했다면, 저장을 한 뒤 upload 폴더 하위에 있는

  • index.js
  • node_modules
들을 zip 형식으로 압축합니다.


압축 후 다시 Lambda 콘솔창으로 이동하여 코드입력유형을 zip파일 형식 업로드를 체크하시고 해당 zip 파일을 업로드 한 뒤 저장하시면 Lamba함수 생성은 모두 완료되었습니다. 

이제 다음 포스팅에서 API Gateway 설정을 마치고 이번 포스팅에서 작성한 Lambda함수를 연결하여 파일업로드를 구현해보겠습니다. 

감사합니다.

댓글

  1. 안녕하세요. 작성하신 포스트 잘 보았습니다.
    한가지 질문이 있는데요.
    포스트대로 작성했더니, s3에 파일이 올라갈때 한글이 깨져서 올라갑니다.
    bodyBuffer를 출력해보면 한글이 정상적으로 나오는데, multipart.Parse를 하게 되면 filename에 한글이 깨져서 들어가있네요.
    한참 헤메다가 해결책을 찾지 못해서 질문드립니다.

    답글삭제
  2. 안녕하세요 님의 글을 잘읽고 있습니다. 그런데 aws에 세팅에서 s3 부분이 클라우드 와치 밑에 안나오고 저장 버튼이 비활성화 인데 어떻게 해야 할까요?

    답글삭제
  3. 안녕하세요 님의 글을 잘읽고 있습니다. 프로젝트 때문에 지금 생성중인데
    aws lambda 콘솔에서 트리거 추가(api-gateway) 는 되는데 s3가 안나타 납니다.
    저장하기 버튼도 비활성화이고요 도움 요청드립니다.

    답글삭제

댓글 쓰기

주간 인기글

[정보] 인스타그램은 당신의 소리를 '듣고' 있을 수도 있습니다

남산 케이블카 이야기

[Angular] 모델, 값이 바뀌었는데 화면 template 이 업데이트 되지 않을 때 조치 팁

안드로이드에서 당겨서 새로고침(SwipeRefreshLayout) 쉽게 구현하기

Java8 Stream 가이드