2019년 2월 27일 수요일

[AWS] 프론트엔드 개발자가 혼자 웹어플리케이션 만들기. #4. AWS API Gateway, Lambda, DynamoDB를 이용한 REST API 구현

[AWS] 프론트엔드 개발자가 혼자 웹어플리케이션 만들기. #4. AWS API Gateway, Lambda, DynamoDB를 이용한 REST API 구현


  이번 포스팅에서는 AWS의 Serverless(서버리스) 서비스들을 이용해서 REST API를 만드는 방법을 정리해보려합니다.

  REST API라 하면, API를 호출할 수 있는 endpoint와, 호출과 함께 전달되는 데이터를 가공 및 처리할 수 있는 로직, 그리고 로직에 따라 데이터가 저장되거나 읽혀지는 데이터베이스가 기본 구성이 될 것입니다.
  이와 같은 기본 구성은 AWS Serverless 서비스들로 구현 가능합니다. endpoint를 생성 할 수 있는 API Gateway, 로직을 담당하는 Lambda, 데이터베이스는 DynamoDB가 담당합니다.


1. DynamoDB 테이블 생성

  먼저, 데이터를 저장하기 위한 데이터베이스로 DynamoDB 테이블을 생성합니다.
  DynamoDB는 AWS의 완전관리형 비관계형(NoSQL) 데이터베이스 서비스입니다. DynamoDB는 테이블 생성이 매우 간단하고, 인스턴스를 구동하는 방식이 아니기 때문에 RDS 처럼 인스턴스 스펙을 무엇으로 할지 고민할 필요가 없으며, 목표 처리량을 설정하기만 하면 나머지는 시스템에서 자동으로 처리합니다.

  DynamoDB는 Console에서 테이블만 생성하면 데이터베이스 구축 완성입니다. 우선, DynamoDB 대시보드에서 '테이블 만들기'를 클릭합니다.

(그림) DynamoDB 테이블 만들기


  첫 단계로 테이블 생성을 위한 정보를 입력하는데, '테이블 이름'을 입력하고 '기본키'에서 '파티션 키'의 이름과 타입만 입력해도 됩니다. 필요에 따라서 '정렬 키'를 추가할 수도 있습니다. '파티션 키'만 입력한다면, '파티션 키'만으로 저장된 항목 하나를 식별할 수 있어야합니다. 하지만 '정렬 키'를 추가한다면, '파티션 키'와 '정렬 키'의 쌍으로 저장된 항목 하나를 식별할 수 있습니다.
  입력 후에는 하단에 '생성' 버튼을 클릭합니다.

(그림) 테이블 생성을 위한 정보 입력


  이로써 테이블 생성이 끝났습니다. 테이블이 생성되면, 대시보드 좌측 리스트에 테이블이 나타나며, 테이블을 선택했을 때 우측에 나타나는 탭 중에서 '항목' 탭이 저장된 데이터를 볼 수 있는 탭입니다.

(그림) 테이블 생성 완료


2. Lambda Function 생성

  데이터베이스가 준비되었다면, 해당 데이터베이스에 데이터를 Create, Read, Update, Delete 할 수 있는 로직을 수행할 Lambda Function(함수)를 생성할 차례입니다.

  Lambda 대시보드에서 '함수 생성' 버튼을 클릭해서 Lambda Function 생성 절차를 시작합니다.

(그림) Lambda Function 생성 시작

  Lambda Function을 만드는 옵션은 총 3가지가 있습니다. 첫번째는 코드를 처음부터 새롭게 작성하는 '새로 작성' 옵션, 두번째는 AWS에서 미리 작성해둔 템플릿을 기반으로 코드를 작성하는 '블루프린트' 옵션, 세번째는 AWS 사용자들이 만들고 공유한 템플릿을 기반으로 코드를 작성하는 '서버리스 애플리케이션 리포지토리' 옵션입니다. 세번째 옵션은 최근에 새로 추가되었습니다.
  이번 포스팅에서는 '새로 작성'을 선택하겠습니다. 그런 다음, Function 생성을 위한 기본 정보를 입력합니다. Function의 이름을 입력하고 런타임을 선택하고 역할(Role)을 선택합니다. 이때의 역할은 현재 생성할 Function이 가지는 권한입니다. 만일 이 Function이 DynamoDB에 접근해야한다면 역할에 DynamoDB에 접근할 수 있는 정책(Policy)이 포함되어 있어야합니다.
  정보가 다 입력되면 하단에 '함수 생성'을 클릭합니다

(그림) Lambda Function 생성을 위한 정보 입력


  '함수 생성'을 누르고나면 Function의 코드를 작성할 수 있는 페이지가 나옵니다. 그곳에 원하는 동작을 하는 코드를 작성하면 됩니다. 아래 코드는 런타임이 Node.js 6 일때, DynamoDB에 기본적으로 CRUD하는 코드 예시입니다. 코드의 주석에서 중요 코드를 설명하겠습니다.

'use strict';

// DynamoDB에 접근할 수 있는 객체 생성
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();

// API Gateway를 이용해서 Lambda Function을 호출할 때,
// Query String이나 Request Body의 데이터는 handler 함수의 event 매개변수로 전달되어옵니다.
exports.handler = (event, context, callback) => {

  // handler 함수의 callback 매개변수를 이용해서 Lambda에서 API Gateway로 Response를 전달할 수 있습니다.
  const done = (err, res) => callback(null, {
    statusCode: err ? '400' : '200',
    body: err ? err.message : JSON.stringify(res),
    headers: {
      'Content-Type': 'application/json',
    },
  });

  // event 객체에는 API Gateway로 호출받은 HTTP Reqeust가 어떤 method인지 저장되어 있습니다.
  // 아래 코드는 HTTP method에 따라 DynamoDB에 CRUD하는 작업을 수행하는 부분입니다.
  switch (event.httpMethod) {
    case 'DELETE':
      dynamo.deleteItem(JSON.parse(event.body), done);
      break;
    case 'GET':
      dynamo.scan({ TableName: event.queryStringParameters.TableName }, done);
      break;
    case 'POST':
      dynamo.putItem(JSON.parse(event.body), done);
      break;
    case 'PUT':
      dynamo.updateItem(JSON.parse(event.body), done);
      break;
    default:
      done(new Error(`Unsupported method "${event.httpMethod}"`));
  }
};


  DynamoDB의 라이브러리에 대한 내용은 링크에서 확인가능합니다. Node.js용 DynamoDB SDK 확인은 여기에서 가능합니다. SDK 문서를 보면서 원하는 동작을 찾아가시면 됩니다.

  코드를 다 작성하고 '저장'을 누르면 Lambda도 준비가 끝났습니다.


3. API Gateway 생성

  이번에는 위에서 작성한 Lambda Function을 호출할 수 있는 endpoint를 만들기 위해서 API Gateway에서 API를 생성하는 방법을 정리합니다. API Gateway로 API를 생성하면 https를 지원하는 URL 형식의 endpoint를 받을 수 있습니다. 그래서 이 endpoint를 axios 같은 http request 라이브러리에서 사용할 수 있습니다.

  API Gateway 대시보드에 들어가서 'API 작성'을 클릭하여 API 생성 절차를 시작합니다.

(그림) 'API 작성' 클릭


  API 생성의 첫 단계는 생성할 API의 정보를 입력하는 것입니다. 새 API를 만들기 위해서는 'API 이름'만 필수로 입력하면 됩니다.
  '엔드 포인트 유형'은 링크를 참고해서 서비스에 맞게 적절히 선택하시면 됩니다. 여기서는 기본값인 '지역'을 선택하겠습니다.

(그림) API 생성을 위한 정보 입력


  API가 생성이되면 아래 그림처럼 '리소스' 영역에 Root Path ('/')가 나타납니다. 아래 그림의 /file 이나 /test는 제가 연습삼아 미리 추가한 것이고, 최초 API 생성 후에는 Root Path만 있습니다. 이 Root Path 하위에 여러 리소스들을 생성해서 여러 REST API URL을 만들어냅니다.
  새로운 하위 Path를 만들기 위해서는 Root Path를 선택한 상태에서 '작업' > '리소스 생성'을 선택합니다.
(그림) '리소스 생성' 선택


  리소스 생성하기 위해서는 '리소스 이름'만 입력하면 됩니다. '리소스 경로'는 리소스 이름을 따라 자동으로 입력되므로 새로 입력할 필요는 없습니다. CORS 활성화는 여기서 체크하지 않아도 됩니다. 어차피 나중에 메서드들을 생성하고 새로 활성화해줘야 하기 때문입니다.

(그림) '리소스 이름' 입력


  리소스를 생성하면 새로운 하위 path가 생성된 것입니다. 이제 이 path가 지원하는 http method를 생성해야합니다. 그러기 위해서 생성한 리소스를 선택한 상태에서 '작업' > '메서드 생성'을 선택합니다.

(그림) '메서드 생성' 선택


  생성할 메서드를 선택하고 체크 버튼을 클릭하면, 메서드 생성을 위한 정보를 입력하는 페이지로 이동합니다. 여기서는 위에서 만든 Lambda Function을 호출하기 위해서 '통합 유형''Lambda 함수'로 선택합니다. 그리고 'Lambda 프록시 통합 사용'을 체크하고 Lambda Function을 생성한 리전을 선택하고 생성한 Lambda Function을 선택합니다. 'Lambda 함수' 입력칸에는 텍스트를 입력할 수 있는데 첫글자를 입력하고나면 드랍다운이 나타나서 선택할 수 있습니다.

(그림) 생성할 메서드 선택

(그림) 생성할 메서드로 호출할 Lambda 함수 선택


  메서드 정보를 저장할 때, 권한에 대한 확인창이 나타나는데, '확인'을 눌러주면 됩니다.

(그림) Lambda Function 호출을 위한 권한 추가


  새로운 리소스와 메서드를 생성했다면, 'CORS 활성화'를 해주어야합니다. 그래야 브라우저에서 다른 도메인 간의 호출이 가능해집니다. CORS 활성화 페이지에서는 별도의 설정이 필요한 상황이 아니라면 바로 'CORS 활성화 및 기존의 CORS 헤더 대체' 버튼을 클릭합니다.

(그림) 'CORS 활성화'

(그림) 대체 버튼 클릭

(그림) 재확인 창에서 다시 버큰 클릭


  사실 가장 많이 실수 하는 부분이 이 부분일것 같습니다. API를 생성하고 온갖 설정을 했지만, 현재는 실제 사용할 수 없습니다. 설정이 끝난 API는 'API 배포'를 해야만 실제로 사용할 수 있습니다. 배포를 위해서는 '작업' > 'API 배포'를 선택합니다.

(그림) 'API 배포' 선택


   API 배포는 스테이지(Stage)를 지정해서 배포할 수 있습니다. 스테이지를 이용하면, 개발단계의 API와 운영단계의 API의 호출 URL을 구분할 수 있습니다. 예를 들어서 방금 전에 만든 API를 실제 운영단계에서 사용하기 전에 테스트를 해보고 싶다면, dev 또는 test라는 스테이지에 배포하고 이 스테이지의 호출 URL을 이용해서 미리 테스트 한 다음에 운영단계의 스테이지에 배포합니다.
  아래 그림은 새로운 스테이지를 만드는 화면입니다. '스테이지 이름'만 입력하면 API 배포가 가능하지만, 현재 배포하는 내용이 무엇인지 설명을 쓰는것이 API 관리에는 도움이 됩니다.


(그림) API 배포 


  API를 배포하고나면, 이 API를 호출할 수 있는 호출 URL가 주어집니다. 이 호출 URL과 생성한 리소스의 하위 path를 이용하여 http request를 요청할 수 있습니다. 예를 들어서 호출 URL이 'https://api.test.com/prod' 이고 리소스의 하위 path가 '/content' 라면, http request를 'https://api/test.com/prod/content'로 요청할 수 있습니다.

(그림) 스테이지마다 각각 주어지는 호출 URL



  이로써, API Gateway, Lambda, DynamoDB가 결합된 REST API를 완성했습니다.