Etc/AWS

AWS Lambda + API + DynamoDB 활용하여 Node.js API 만들기

곤프 2022. 3. 7. 18:53

AWS Lambda 함수를 활용한 microservice architecture 맛보기 입니다.

 

Node.js로 Lambda 함수를 만들고,

REST API(POST Method)호출 시, AWS DynamoDB에 데이터를 저장하는것까지 진행합니다.

 

여기저기 강의나 자료를 많이 찾아봤지만 전체 적인 흐름을 이해하지못하니 따라하기 쉽지 않아서

제가 다시 정리하고자 블로그에 등록합니다.

 

작성하려는 API는 제품을 등록하는 API이며 아래와 같이 정의했습니다.

 - 호출 url : http://domain/products

 - Method : Post

 - data : name, price, brand, description

 

Lambda 함수를 만들기 위한 전체적인 흐름은 아래와 같이 이루어 집니다.

 

1. IAM 역할 생성

2. DynamoDB Table 생성

3. Lambda 함수 생성

4. Lambda 테스트 이벤트 생성

5. API Gateway 생성

  5.1 API 리소스 생성

  5.2 API 메서드 생성

  5.3 API 배포

6. Postman을 활용한 최종 테스트

 

시작하겠습니다.

 

 

1. IAM 역할 생성

-> IAM 서비스 콘솔로 진입합니다.

 

-> 왼쪽 메뉴에서 "역할"로 들어가서 "역할 만들기" 버튼을 클릭합니다.

 

-> Lambda에서 사용할 역할이므로 AWS 서비스 - Lambda를 선택합니다.

 

-> 권한추가 화면에서 AWSLambdaBasicExecutionRole 및 AmazonDynamoDBFullAccess을 검색해서 둘다 추가합니다.

-> AWSLambdaBasicExecutionRole는 CloudWatch에 로그를 남기기 위한 권한이고

-> AmazonDynamoDBFullAccess는 dynamoDB에 데이터를 쓰기위한 권한입니다.

    (좀더 세부적으로 권한을 줄 수도 있지만 일단 저렇게 합니다)

 

-> 역할 이름은 적당히 넣어 줍니다.

 

-> 2단계:권한추가 부분에서 AWSLambdaBasicExecutionRole 및 AmazonDynamoDBFullAccess 정책이 보여야 합니다.

-> "역할 생성"을 눌러줍니다.

-> 역할 생성이 완료되었습니다.

 

2. DynamoDB Table 생성

-> DynamoDB 서비스 콘솔로 이동해서 "테이블 생성"을 눌러줍니다.

 

-> 테이블 이름 : Products

-> 파티션 키 : id, 문자열

-> 이외는 기본옵션으로 테이블을 생성합니다.

 

 

3. Lambda 함수 생성

-> Lambda 서비스 콘솔로 이동하여 "함수 생성"을 클릭합니다.

 

-> 함수이름 : addProduct

-> 기본 실행 역할 변경 - 기존 역할 사용 - 1번에서 만든 IAM 역할을 선택합니다.

     (저는 aws-lambda-access로 만들었었습니다.)

 

-> 함수가 만들어졌습니다. 코드 index.js 파일에 아래 내용을 붙여넣습니다.

 

const randomBytes = require('crypto').randomBytes;

const AWS = require('aws-sdk');

const ddb = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    // if (!event.requestContext.authorizer) {
    //   errorResponse('Authorization not configured', context.awsRequestId, callback);
    //   return;
    // }

    const id = toUrlString(randomBytes(16));
    console.log('Received event (', id, '): ', event);

    const req = JSON.parse(event.body);
    
    addProduct(id, req).then(() => {
        callback(null, {
            statusCode: 201,
            body: JSON.stringify({
                id: id,
                Eta: '30 seconds',
            }),
            headers: {
                'Access-Control-Allow-Origin': '*',
            },
        });
    }).catch((err) => {
        console.error(err);

        errorResponse(err.message, context.awsRequestId, callback)
    });
};

function addProduct(id, data) {
    return ddb.put({
        TableName: 'Products',
        Item: {
            id: id,
            name: data.name,
            brand: data.brand,
            price: data.price,
            desc: data.desc,
            createdAt: new Date().toISOString(),
        },
    }).promise();
}

function toUrlString(buffer) {
    return buffer.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}

function errorResponse(errorMessage, awsRequestId, callback) {
  callback(null, {
    statusCode: 500,
    body: JSON.stringify({
      Error: errorMessage,
      Reference: awsRequestId,
    }),
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  });
}

-> 이 소스는 AWS Document에 있는 기본 소스를 제가 테이블이름과 데이터만 조금 수정한것입니다.

 

4. Lambda 테스트 이벤트 생성

-> 테스트 탭으로 이동 후 "이름"에는 addProduct-test를 입력 후 내용에 아래 테스트 코드를 입력하고 "변경 사항 저장"을 클릭합니다.

{
  "path": "/products",
  "httpMethod": "POST",
  "headers": {
    "Accept": "*/*",
    "Authorization": "eyJraWQiOiJLTzRVMWZs",
    "content-type": "application/json; charset=UTF-8"
  },
  "queryStringParameters": null,
  "pathParameters": null,
  "requestContext": {
    "authorizer": {
      "claims": {
        "cognito:username": "the_username"
      }
    }
  },
  "body": "{\"name\":\"아이폰12\",\"brand\":\"Apple\",\"price\":5000000,\"desc\":\"애플의 휴대폰 아이폰 12 입니다.\"}"
}

 

 

-> 다시 코드로 돌아가서 "Deploy"를 클릭 해 소스를 저장한 후 "Test"를 클릭 합니다.

-> Response가 201로 오류 없이 잘 성공했습니다.

 

-> 다시 DynamoDB 서비스 콘솔로 들어가서 Products 테이블의 항목으로 들어가면 방금 생성한 데이터가 1개 잘 보입니다.

 

 

 

이로써 Lambda함수 생성은 끝났습니다.

하지만 함수는 사용하려고 만든것인데 현재로써는 함수를 사용할 방법이 없습니다.

 

그래서 우리는 함수를 사용하기 위해 트리거를 만들어 주어야 합니다.

트리거로 사용하는 방법은 여러개가 있는것 같은데,

우리는 API를 만들어서 API 호출 시 함수가 실행되도록 하겠습니다.

 

 

5. API Gateway 생성

-> API Gateway 서비스 콘솔로 들어와서 "REST API" 항목에서 "구축"을 클릭합니다.

 

-> 위와 같이 설정 후 생성합니다.

 

 

  5.1 API 리소스 생성

-> 작업 - 리소스 생성을 클릭 합니다.

 

-> 리소스 이름에 products 입력 후 생성합니다.

 

 

  5.2 API 메서드 생성

-> products 리소스를 선택 후 "메서드 생성"을 클릭합니다.

 

-> 저희는 등록메서드 이므로 "POST"를 선택 후 체크표시를 누릅니다.

 

-> 통합유형 : Lambda 함수, Lambda함수:아까 만든 함수명(addProduct)를 입력 합니다.

 

  5.3 API 배포

-> 작업을 누르고 "API 배포"를 클릭합니다.

 

-> 스테이지는 [prod / dev / test / v01, v02]와 같은 버전 등으로 설정합니다.

(최종 api 엔드포인트 주소에 스테이지명이 들어갑니다)

 

-> 기본 값으로 "변경 사항 저장" 클릭 합니다.

 

 

6. Postman을 활용한 최종 테스트

-> Lambda 서비스 콘솔로 가면 addProduct 함수 밑에 API 게이트웨이 트리거가 생겼습니다.

그리고 API 엔드포인트를 복사합니다.

 

-> 포스트맨에서 Post 요청으로 본인의 엔드포인트 주소와 raw 데이터를 넣고 센드를 누르면 결과가 리턴됩니다.

-> 다행히 201로 성공한 것 같군요.

 

아래는 포스트맨 raw 데이터 입니다.

{
  "path": "/products",
  "httpMethod": "POST",
  "headers": {
    "Accept": "*/*",
    "Authorization": "eyJraWQiOiJLTzRVMWZs",
    "content-type": "application/json; charset=UTF-8"
  },
  "queryStringParameters": null,
  "pathParameters": null,
  "requestContext": {
  },
  "body": "{\"name\":\"포스트맨\",\"brand\":\"등록테스트!!@!\",\"price\":5000000,\"desc\":\"애플의 휴대폰 아이폰 12 입니다.\"}"
}

-> AWS DynamoDB 서비스 콘솔에서 테이블에 항목을 보면 정상적으로 등록되었습니다.

 

 

수고하셨습니다.

 

AWS 콘솔 화면이 계속 바껴서 따라하기가 힘든데

모두들 성공하셨으면 좋겠습니다.

 

 

참조 url

https://aws.amazon.com/ko/getting-started/hands-on/build-serverless-web-app-lambda-apigateway-s3-dynamodb-cognito/