Site icon GRIP.News

AWS, Lambda + API Gateway 를 이용한 RESETful API 개발 #2

앞선 포스트에서 기본적인 Lambda Function 을 만들었고, 외부와 통신할 수 있는 인터페이스. API Gateway 를 생성해 랑데뷰함으로서, ‘나 살아있어요!’ 를 성공적으로 전달했다. 이제 한걸음 더 RDS/Aurora 와 연결해 볼 차례다.

AWS, Lambda + API Gateway 를 이용한 RESETful API 개발 #1

AWS Lambda 의 가장 큰 장점은 ‘확장성’ 이다. 내가 선택한 언어에 라이브러리를 설치함으로서, 기능을 편리하게 확장할 수 있다. “AWS, Lambda + API Gateway 를 이용한 RESETful API 개발 #2” 의 목표는 사용자의 요청을 받아(API Gateway) Lambda 에서 선언한 함수(Lambda Function)가 데이터베이스(RDS/Aurora)에 접근해 상호 적용하는 구조 구현이다.

 

앞서 Lambda Function 의 언어로 NodeJS 를 선택했다. NodeJS 에서 MySQL 을 사용하려면 MySQL 라이브러리가 필요하다. 안타깝게도 Lambda 코드-에디터는 “npm install”과 같은 명령어 실행이 불가하기 때문에, 로컬에 필요한 라이브러리를 설치하고 Lambda 에 업로드해야 한다. 즉, 로컬에 NodeJS 가 설치 되어 있어야 한다.

 

MySQL 라이브러리 설치 및 코딩


Lambda에 업로드 할 기본 환경을 로컬에 구축한다. node_modules 폴더만 압축해 등록하고, 코드-에디터로 코딩해도 되지만, 최소한의 코드는 로컬에서 작업하고 업로드하는게 여러모로 편리하다. (당연하지만, VSCode 같은 에디터가 사용성이 훨신 좋기 때문이다)

package.json 만들기

PS C:\Works\Lambda> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (lambda) onelabs-npd-connector
version: (1.0.0) 0.0.1
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to C:\Works\Lambda\package.json:

{
  "name": "onelabs-npd-connector",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) yes

 

MySQL 연결을 위한 라이브러리를 설치한다.

PS C:\Works\Lambda> npm install mysql --save
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN onelabs-npd-connector@0.0.1 No description
npm WARN onelabs-npd-connector@0.0.1 No repository field.

+ mysql@2.17.1
added 11 packages from 15 contributors and audited 13 packages in 1.541s
found 0 vulnerabilities

 

MySQL 의 접속 정보를 보관하고 있는 설정 파일, config.json 을 만든다. 복수의 접속 정보를 사용하는 경우 코드가 복잡해 지기 때문이다.

config.json

{
    "npd":{
        "host":"mtlabs.rds.amazonaws.com",
        "user":"username",
        "password":"password",
        "database":"databasename"     
    }    
}

 

‘로컬’에서 실행 할 수 있는 코드를 먼저 만들자.  node 로 직접 실행 가능한 구조여야 한다. 내용은 간단하다. MySQL 에 접속 여부를 확인할 수 있는 ping (SELECT 1)에 대한 응답에 따라 데이터베이스 상태를 확인할 수 있다.

local.js

const mysql     = require('mysql');
const config    = require('./config.json');

const mysqlPool = mysql.createPool ({ 
    host    : config.npd.host, 
    user    : config.npd.user,
    password: config.npd.password,
    database: config.npd.database,
    connectionLimit : 60
});

const createResponse = (status, body) => ({
    statusCode: status,
    body: JSON.stringify(body)
  });

mysqlPool.getConnection(function(err, connection){
    if(err !== null)
        return console.log(createResponse(500, {message: err}));

    connection.query('SELECT 1 AS RESULT', function(error,results,field) {
        connection.release();
        if(error !== null) 
            return console.log(createResponse(500, {message: error}));
        console.log(createResponse(200, {message: results[0].RESULT}));
    });
});

실행결과

# 문제가 없다면 200 이 리턴될 것이다.
PS C:\Works\Lambda> node .\index.js
{ statusCode: 200, body: '{"message":1}' }


# 어떠한 문제가 있다면 에러 메시지와 함께 500이 리턴된다.
PS C:\Works\Lambda> node .\index.js
{ statusCode: 500,
  body:
   '{"message":{"code":"ER_PARSE_ERROR","errno":1064,"sqlMessage":"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \'\\"SELECT 1 AS RESULT\' at line 1","sqlState":"42000","index":0,"sql":"\\"SELECT 1 AS RESULT"}}' }

 

Lambda 에 등록할 파일을 만든다. 기본적인 구조는 같지만, 핸들러를 추가하고, Lambda 를 위한 변수를 추가한다. 이 코드는 핸들러를 호출하지 않기 때문에 로컬에서 실행할 경우 어떠한 값도 출력하지 않는다.

index.js

const mysql     = require('mysql');
const config    = require('./config.json');

const mysqlPool = mysql.createPool ({ 
    host    : config.npd.host, 
    user    : config.npd.user,
    password: config.npd.password,
    database: config.npd.database,
    connectionLimit : 60
});

const createResponse = (status, body) => ({
    statusCode: status,
    body: JSON.stringify(body)
  });


exports.handler = function(event, context, callback){
    context.callbackWaitsForEmptyEventLoop = false;

    mysqlPool.getConnection(function(err, connection){
        if(err !== null) 
            return console.log(createResponse(500, {message: err})); 
        connection.query('SELECT 1 AS RESULT', function(error,results,field) {
            connection.release();
            if(error !== null) 
                return callback(null, createResponse(500, {message: error}));

            callback(null, createResponse(200, {message: results[0].RESULT}));
        });
    });
};

 

callbackWaitsForEmptyEventLoop = false;

Lambda에서의 CallBack은 기본적으로 Loop 의 모든 작업이 완료 될때 까지 발생하지 않는다. 즉, Empty Event Loop  까지 기다리지 않겠다고 선언한 것.

 

작업이 완료 되었다면 모듈(node_modules)과 작업한 파일 (config.json, index.js)을 zip 파일로 압축하자.

 

 

Lambda  코드 업로드 및 테스트


AWS Lambda Console 을 통해 zip 파일을 등록하면 로컬에서 작업했던 내용이 코드-에디터에 표시된다. 만약 10MB 이상의 파일을 등록할 경우 Timeout 이 발생하는 경우가 있으니, S3 에 올려 URL 을 입력해 등록하는 방법이 있다.

오류주의 (IAM 권한 불충분)

Lambda 를 VPC 에 귀속시켜 저장할 때 “역할에 VPC 권한이 없습니다.(Your role does not have VPC permissions.)” 라는 오류가 발생하는 경우가 있다. 이 경우 선택된 실행 권한에 Lambda 함수를 실행할 수 없는 권한이 없는 경우 발생한다.

기본 IAM 에는 CloudWatch Logs 를 위한 권한만 포함되어 있다. “AWSLambdaVPCAccessExecutionRole” 를 추가하면 해결된다.

 

등록된 코드를 테스트해보자. 테스트 방법은 이전 포스트와 같다. 문제가 없다면 message 는 1이 회신될 것이다.

 

이제 API Request 및 RDS 까지 연결되는 작업이 완료됐다. 조금만 응용한다면 다양한 방식으로 API 를 구현 및 사용 가능하다는거. 그리고 아주 쉽다는 것. 이 다음글에서는 API Gateway 의 기능 확장을 다뤄보고자 한다.

Exit mobile version