2017년 5월 26일 금요일

[AWS] AWS Lambda에서 DynamoDB에 데이터 삽입, 조회, 수정, 삭제 하기.

AWS Lambda에서 DynamoDB에 데이터 삽입, 조회, 수정, 삭제 하기.

이번 포스팅에서는 AWS의 서버리스 컴퓨트 서비스인 Lambda에서, NoSQL 서비스인 DynamoDB에 데이터를 삽입, 조회, 수정, 삭제하는 방법에 대해서 정리해보겠습니다.
Lambda에서는 node.js를 사용했습니다.

1. DynamoDB에서 Table 생성하기

먼저 DynamoDB에 데이터를 넣을 수 있는 Table을 생성합니다.
DynamoDB에서 Table을 생성하는 것은 매우 간단합니다.
중요한 것은 Partition Key가 관계형데이터베이스의 Primary Key라고 생각하시면 되는 것 입니다.
그리고 선택적으로 Sort Key를 추가하면 Partition Key와 Sort Key가 복합으로 Primary Key키로써 테이블 내에서 하나의 항목(Item)을 식별하는데 사용됩니다.
Table을 만들때는 단지, Table의 이름과 Partition Key, Sort Key를 지정해주면 끝납니다.
물론, 더 세세한 설정이 가능하지만 이번 포스팅에서는 기본설정으로 사용하도록 하겠습니다.
(저도 초보자라서 자세한 설정은 아직 지식이 깊지 않아서요..ㅎㅎ)

2. Lambda에서 DynamoDB에 접근하기

두 소제목으로 정리하겠습니다.
첫번째는 Lambda 코드에서 DynamoDB에 데이터를 삽입, 조회, 수정, 삭제하는 함수이고,
두번째는 함수의 인자로 넘길 변수의 메세지 포맷(Json 형식)입니다.

2-1. Lambda 코드

여기서 설명은 코드내에서 주석으로 정리하겠습니다.
'use strict';

console.log('Loading function');

// DynamoDB를 사용하기 위해서 아래 2줄을 꼭 추가시켜줘야합니다.
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {
    
    // DynamoDB에 데이터를 조작한 뒤에 그 결과를 받아서 Lambda함수를 return 시킬 콜백함수입니다.
    // 이 예제에서는 처리결과코드(statusCode)와 처리내용(body)를 본 Lambda함수의 결과로 반환합니다.
    const done = (err, res) => callback(null, {
        statusCode: err ? '400' : '200',
        body: err ? err.message : JSON.stringify(res),
    });

    // 아래 2-2에서 설명드리겠지만 저는 이 람다함수를 수행하기 위해서 요청 payload에 method 항목을 넣었습니다.
    // 이 method는 post, get, put, delete 값을 가지고 그에 따라 분기합니다.
    switch (event.method) {
        case 'DELETE':
            // DynamoDB에서 Item을 삭제 시킬 때는 deleteItme 함수를 이용합니다.
            // 함수 호출에 필요한 메세지를 첫번째 인자로 넘기고, 두번째 인자에 결과를 받을 콜백함수를 넣어줍니다.
            // 인자는 모든 함수가 동일합니다. 다만 메세지의 포맷이 조금씩 변경될 뿐입니다. 그 내용은 아래 2-2에서 정리하겠습니다.
            dynamo.deleteItem(event.body, done);
            break;
        case 'GET':
            // (1) Read Item : Key를 알고 있는 한 Item을 가져옵니다.
            dynamo.getItem(event.body, done);

            // (2) Query Data : 조건에 만족하는 일부 Item들만 가져옵니다.
            //dynamo.query(event.body, done);

            // (3) Scan Data : 지정한 테이블의 전체 Item들을 가져옵니다.
            //dynamo.scan(event.body, done);
            break;
        case 'POST':
            // 새로운 Item을 추가할 때는 putItem 함수를 사용합니다.
            dynamo.putItem(event.body, done);
            break;
        case 'PUT':
            // Item의 내용을 수정할 때는 updateItem 함수를 사용합니다.
            dynamo.updateItem(event.body, done);
            break;
        default:
            done(new Error(`Unsupported method`));
    }
};

2-2. 함수의 첫번째 인자로 넘기는 메세지 포맷

Lambda에서 DynamoDB를 조작할 때는 함수에 Json 형식의 메세지를 넘기게 되는데,
삽입, 조회, 수정, 삭제 각 경우에 따라서 메세지에 담아야할 항목들이 조금씩 다릅니다.
이번에는 이 때 각각 어떤 항목이 기본적으로 필요한지 정리하겠습니다.
Lambda함수의 테스트를 위해서 아래와 같은 기본 포맷을 사용했습니다.
method는 제가 Lambda 코드에서 분기 시키기 위해서 넣어 놓은 것이고,
중요한 것은 body항목의 값으로 들어가 있는 부분 입니다.
위에서 제시한 예제에서도 DynamoDB에 이 body부분만 추출해서 인자로 넣습니다.
{
    "method":"POST",
    "body":{...}
}
아래의 코드들은 body부분만 작성한 것이니 주의해주시기 바랍니다.

(1) 삽입(putItem)

{
    "TableName":"{테이블 이름}",
    "Item":{
        "{Partition Key}":"{추가할 값}",
        "{Sort Key}":"{추가할 값}",
        "{기타 추가할 Attribute}":"{추가할 값}"
    }
}
삽입에서 꼭 필요한 항목은 TableName과 Item입니다.
꼭 대소문자 확식하게 구별해주셔야합니다. 안그러면 에러나서 안됩니다.
Partition Key는 필수로 넣어주셔야하고, Sort Key도 설정하셨다면 필수로 넣어주셔야합니다.
그외 넣고싶은 Attribute를 Json 형식으로 마음껏 넣으셔도 됩니다.
참고로, 아시다시피 값이 숫자라면 쌍따옴표로 묶어줄 필요없이 숫자만 기입하셔도 됩니다.
오히려 Partition Key 또는 Sort Key의 자료형을 숫자(Number)로 했는데 숫자값을 쌍따옴표로 묶었다면 에러가 발생합니다.

(2) 조회

조회는 3가지가 있습니다.
Key를 알고있어서 바로 딱 한 Item만 조회하는 방법, Query를 이용해서 일부 Item들을 조회하는 방법, 전체 Item을 조회하는 방법입니다.
명명하는 것을 구분하기 위하여, 한 Item만 가져오는 것을 Read Item, 일부 Item들을 가져오는 것을 Query Data, 전체 Item들을 가져오는 것을 Scan Data라고 하겠습니다.
(1) Read Item
{
    "TableName": "{테이블 이름}",
    "Key": {
        "{Partition Key}":"{찾을 값}",
        "{Sort Key}":"{찾을 값}"
    }
}
Key를 알고 있는 상태에서 해당 Key에 해당하는 특정 Item만 가져오기를 원할 때는 getItem()함수를 사용합니다.
그리고 요청에는 TableName과 Key 정보만 넘기면 됩니다.
(2) Query Data
{
    "TableName": "{테이블 이름}",
    "KeyConditionExpression":"{찾으려는 Partition Key} = :{변수명1} and {찾으려는 Sort Key} between :{변수명2} and :{변수명3}",
    "ExpressionAttributeValues" : {
        ":{변수명1}":"{찾을 값1}",
        ":{변수명2}":"{찾을 값2}",
        ":{변수명3}":"{찾을 값3}"
    }
}
특정 한개의 Item이 아니라 조건식을 이용해서 조건에 해당하는 모든 Item들을 조회하고자 할때는 query()함수를 사용합니다.
여기서는 중요한 점이, Partition Key는 오직 등식 조건(=)만 가능하다는 것입니다. 그리고 Sort Key에 비교 연산자 사용이 가능합니다. Sort Key에 사용 가능한 비교 연산자는 아래 링크에서 확인 가능합니다.
(링크 : http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions)
참고로, Query를 날렸는데 Key명이 예약어라서 오류가 난다면 ExpressionAttributeNames에 대해 알아보시기 바랍니다.
추가적으로, 일반 Attribute를 사용하여 Query를 날리고 싶을 때는, 해당 Attribute를 GSI(Global Secondary Indexes)로 설정하면 됩니다.
GSI에 설정하고 나면, 위 json형식에서 단지 IndexName만 추가하면 됩니다.
{
    "TableName": "{테이블 이름}",
    "IndexName": "{GSI생성 시에 설정한 Index 이름}",
    "KeyConditionExpression":"{찾으려는 Partition Key} = :{변수명1} and {찾으려는 Sort Key} between :{변수명2} and :{변수명3}",
    "ExpressionAttributeValues" : {
        ":{변수명1}":"{찾을 값1}",
        ":{변수명2}":"{찾을 값2}",
        ":{변수명3}":"{찾을 값3}"
    }
}
(3) Scan Data
{
    "TableName": "{테이블 이름}"
}
Table의 모든 Item을 조회할 때는 scan()함수를 사용합니다.
그리고 scan할때는 기본적으로 TableName만 지정하면 해당 Table의 모든 Item을 조회할 수 있습니다.
선택적으로 Filter를 추가할 수는 있습니다.
{
    "TableName": "{테이블 이름}",
    "FilterExpression":"{찾으려는 Attribute} between :{변수명1} and :{변수명2}",
    "ExpressionAttributeValues" : {
        ":{변수명1}":"{찾을 값1}",
        ":{변수명2}":"{찾을 값2}"
    }
}
Filter를 이용하면 일부 Item만 조회하는게 가능한데, 이는 Query Data와 유사합니다.
다만 차이점이 있는데, 첫째, Key 뿐만 아니라 다른 일반 Attribute로도 조회가 가능하다는 점. 둘째, Query Data에서는 Partition Key에 등식 조건(=)만 사용 가능했는데, Scan Data에서는 Filter를 이용하면 Partition Key에 비교 연산자를 사용하여 일부 Item만 조회하는게 가능합니다.
여기서 사용할 수 있는 비교 연산자는 Query Data에서 Sort Key에 적용할 수 있는 것과 동일 한 것 같습니다.

(3) 수정

{
    "TableName":"{테이블 이름}",
    "Key":{
        "{Partition Key}":"{찾을 값}",
        "{Sort Key}":"{찾을 값}"
    },
    "UpdateExpression":"set {변경할 Attribute1} = :{변수명1}, {변경할 Attribute2} = :{변수명2}",
    "ExpressionAttributeValues":{
        ":{변수명1}":"{변경할 값1}",
        ":{변수명2}":"{변경할 값2}"
    },
    "ReturnValues":"UPDATED_NEW"
}
수정에서는 필수로 넣어줘야하는 항목이 4개입니다.
TableNameKeyUpdateExpressionExpressionAttributeValues입니다.
TableName은 수정을 원하는 테이블의 이름이며, Key는 수정할 데이터를 찾기 위한 Partition Key와 Sort Key를 알려주는 곳입니다.
UpdateExpression은 변경할 데이터의 Attribute를 지정하는 곳입니다.
ExpressionAttributeValues에서 변수들과 값들을 매칭시킵니다.
ReturnValues는 선택 항목인데, 이 항목이 없으면 수정 요청이 성공해도 아무런 응답값이 없지만, 이 항목의 값을 UPDATED_NEW로 하면 수정한 값이 응답으로 되돌아 옵니다.

(4) 삭제

{
    "TableName":"{테이블 이름}",
    "Key":{
        "{Partition Key}":"{찾을 값}",
        "{Sort Key}":"{찾을 값}"
    }
}
삭제는 테이블 이름과 키만 넘기면 바로 삭제 됩니다. Sort Key를 설정하지 않았다면 Partition Key만 입력하시면 됩니다.
지금까지 읽어주셔서 감사합니다.
여러분의 정보 습득에 도움이 되었길 바랍니다.
혹여, 틀린 내용이나 보충되야할 내용이 있다면 댓글 달아주시면 바로 확인하고 보완하도록 하겠습니다.
감사합니다.

참고 링크
AWS Doc
AWS DynamoDB Query 상세
AWS DynamoDB Scan 상세

2017년 5월 25일 목요일

[JAVA] String의 equals 메서드에 대한 한가지 Tip

Java에서, String의 equals 메서드에 대한 한가지 Tip



Java를 하는 사람은 다들 알 듯이 String형의 값의 비교는 동등 비교(==)를 사용하면 안되고 equals 메서드를 사용해야합니다.

이때 한가지 주의해야할 Tip이 있습니다.

우선 소스를 보겠습니다.

1 : final String FINAL_STRING = "hello world";
2 : String str = null;
3 :   
4 : if(FINAL_STRING.equals(str)) {
5 :  System.out.println("문자열 값이 같습니다.");
6 : }else{
7 :  System.out.println("문자열 값이 다릅니다.");
8 : }
9 :  
10: if(str.equals(FINAL_STRING)) {
11:  System.out.println("문자열 값이 같습니다.");
12: }else{
13:  System.out.println("문자열 값이 다릅니다.");
14: }

우선 2개의 String형 변수가 있습니다. 하나는 FINAL_STRING 이라는 문자상수고 하나는 str라는 변수입니다.

위 코드를 실행하면 4번 라인의 조건문은 정상적으로 수행되고 10번라인의 조건문은 에러가 발생합니다.
문자열 값이 다릅니다.Exception in thread "main" 
java.lang.NullPointerException
 at helloworld.HelloWorld.main(HelloWorld.java:10)

보시다시피 equals 메서드의 인자에는 null 값이 들어가도 되지만 equals 메서드를 호출하는 변수는 null이면 예외가 발생합니다.

이를 실제로 적용하시는 경우는 이런 경우가 있습니다.
사용자로부터 값을 입력받거나 하는 등 값이 변하는 String형 변수가 있고, 그 변수의 값을 프로그램이 고정으로 사용하는 문자열과 값 비교를 한다면, 꼭 고정된 문자열에서 equals 메서드를 호출하고 동적으로 변할 수 있는 변수를 인자로 넣어줘야 예외가 발생하지 않습니다.

동적으로 변하는 String형 변수에 절대적으로 null이 들어오지 않는다라는 확신이 있다면 아무렇게나 해도 되겠지만 혹시나 만에하나라도 null이 생길수 있는 경우를 대비해서 절대적으로 null이 될 수 없는 문자 상수나 프로그램 내에서 고정적으로 문자열을 할당한 변수를 equals 앞에 써주는게 좋습니다.

결론,
{절대null이 되지 않는 String}.equals(null이 될수도 있는 String)

2017년 5월 10일 수요일

[AWS] AWS API Gateway와 Lambda를 이용한 REST API 만들기

AWS API Gateway와 Lambda를 이용한 REST API 만들기

이번 포스팅에서는 AWS의 API Gateway와 Lambda를 이용해서 REST API를 만들어보겠습니다.
또한, REST API는 AWS Cognito로 로그인한 사용자에게만 사용 가능하도록 할 것입니다.
실습 과정에서 Cognito로 만든 User Pool이 필요합니다. 미리 만들고 본 포스팅을 보시면 좋을 것 같습니다.
AWS Cognito로 로그인 시스템을 만드는 방법은 이전 포스트에서 다루었습니다. 아래 링크를 참고해주시기 바랍니다.
(AWS Cognito 사용법 : https://walkinpcm.blogspot.kr/2017/05/aws-aws-cognito.html)
기초적인 실습이라서 입문자에게 도움이 되는 글일 듯 싶습니다.
(제가 입문자라서 입문용 글을 쓰고 있습니다..ㅎㅎ)

1. API Gateway와 Lambda의 개념

1-1. API Gateway

AWS API Gateway는 손 쉽게 REST API의 URI 주소를 생성할 수 있고, 유지 관리, 모니터링 할 수 있는 서비스입니다.
톰캣의 서블릿으로 예를 들면,
http(s)://{서버의 주소}/{서블릿명} 처럼 Resource에 접근할 수 있는 인터페이스라고 할 수 있습니다.
다만, API Gateway는 웹서버가 필요 없고, API 호출에 대한 로그도 쉽게 볼 수 있는 등 여러 장점이 있는 서비스라고 할 수 있습니다.

1-2. Lambda

Lambda는 최근 인기가 상승하고 있는 Serverless Compute Service입니다.
역시 톰캣으로 예를 들면, 서블릿의 역할을 수행하는 서비스라고 할 수 있습니다.
즉, 기존의 서버에서 동적으로 수행되는 특정 기능을 서버 없이 만들 수 있는 서비스인 것입니다. (엄밀히는 AWS가 서버를 운영하는 거겠지만, 사용자 입장에서 서버가 없다는 것입니다.)

2. 실습 상황

이번 포스팅에서 진행할 실습의 상황은 다음과 같습니다.

  1. 웹브라우저에서 사용자 인증을 위한 Token과 데이터를 가진 Payload를 붙여서 POST 요청을 보냅니다.
    (API의 호출 권한을 Open으로 해 놓으면 Token은 필요없습니다. Token을 API Gateway의 API Key로도 설정할 수 있지만, 본 포스팅에서는 AWS Cognito를 이용한 User의 Token으로 설정할 것입니다.)
  2. API Gateway는 Token을 확인하여 적법한 사용자라고 판별되면 Lambda Function을 호출하여 POST 요청에 대한 동작을 수행하게 합니다.
  3. Lambda는 적절한 동작을 수행 한 뒤 응답을 API Gateway로 보냅니다.
  4. API Gateway는 Lambda에게 받은 응답을 그대로 웹브라우저에게 응답합니다.

3. 실습

이제 step by step으로 정리해보겠습니다.

3-1. Lambda function과 API 만들기를 시작합니다.

AWS Lambda를 만드는 과정에서 API Gateway를 바로 연결 시켜서 API까지 만들 수 있습니다.
그래서 가장 먼저, AWS Lambda 서비스로 들어가서 'Get Started Now'를 클릭합니다.
이미 만들어본 적이 있으시면 Function을 새로 만드는 버튼을 찾아서 누르시면 됩니다.

3-2. Function 탬플릿을 선택합니다.

AWS Lambda는 맨땅부터 코딩할 수도 있지만, 목적에 따라 미리 만들어진 탬플릿을 골라서 생성할 수도 있습니다.

보시다시피 탬플릿이 참 많은데요. Filter부분에 키워드를 검색하시면 알맞은 탬플릿을 금방 찾으실 수 있습니다.


본 포스팅은 입문을 위하여 정리하기에 탬플릿 중에 'hello-world' 탬플릿을 선택하겠습니다.
파이썬으로 된 탬플릿도 있지만 저는 노드를 선택했습니다.

3-3. Lambda의 Trigger로 API Gateway를 선택합니다.

Lambda를 생성하면서 바로 Trigger를 선택하고 함께 생성할 수 있습니다.
빨간색 네모박스 부분을 클릭하시면 Trigger로 사용할 수 있는 종류가 나옵니다.
저는 API Gateway를 선택했습니다.

3-4. API Gateway 이름을 지정합니다.

'API name'에 원하는 API이름을 입력합니다. 이 이름으로 나중에 URL이 만들어 지지는 않습니다. URL은 Lambda function 이름으로 설정됩니다. 그러니 여기서는 API를 구분할 목적으로 입력하시면 되겠습니다.
'Deployment stage'는 나중에는 API의 버전 관리를 하게되면 세분화 해서 나누지만 본 포스팅에서는 입문을 빠르게 할 목적으로 일단 prod 하나만 사용하겠습니다.
'Security'는 Open으로 하셔도 되고 아무거나 하셔도 됩니다. 나중에 Cognito로 변경할 것이기 때문입니다. 저는 그래도 Open은 아무나 막 쓸수 있다는 생각에 Open with access key를 선택했습니다.

3-5. Lambda Function 이름을 지정합니다.

API 설정 다음으로 Lambda Function에 대한 설정을 합니다.
'Name'에 원하는 이름을 입력해주세요. 이 이름이 URL에 사용됩니다.
'Runtime'은 저는 노드를 선택했습니다. 여러분은 원하는 것을 선택하셔도 좋습니다.

3-6. Lambda Function의 코드를 보기만하고 넘어갑니다.

일단 코드는 보기만 하고 넘어갑니다. 뒤에서 수정할 것입니다.
코드를 간략히 설명하자면, Input으로 들어온 Body에서 key1, key2, key3의 값을 로그로 출력하고 Lambda Function의 응답으로 key1의 값을 반환합니다.
부가적으로 밑에 'Environment Variables'가 있는데, 이는 자주 또는 가끔 변경이 잘 되는 변수를 하드코딩하지 않고 환경변수로 두어서 값의 변경이 일어나도 코드 수정없이 반영할 수 있게 해주는 기능입니다.
Tip을 드리자면 노드 기준으로 환경변수를 사용하기 위해서는 process.env.환경변수명으로 코드에서 사용하실 수 있습니다.
보기만하고 지나간다고했는데 말이 길었네요 ㅎㅎ

3-7. Role을 설정합니다.

Role은 Lambda Function에서 다른 AWS 서비스에 접근하기 위하여 필요합니다.
기본적으로 Lambda에서는 Log를 남길수 있는 Role(권한)을 가지고 있습니다. 여기서 설정하는 Role은 추가적으로 필요한 Role을 설정하는 것입니다.
처음에는 만들어진 Role이 없을 것이므로 'Create new role from template(s)'를 선택합니다.
'Role name'은 적절하게 원하는 이름 붙여주시면 됩니다.
'Policy templates'는 그림에 써넣은대로 더 추가하고 싶은 Role을 여러개 선택할 수 있는데, 본 포스팅에서는 hello world 실습이므로 다른 AWS 서비스에 접근할 일이 없어서 아무것도 선택하지 않았습니다.
부가적인 설명으로, 맨 위에 'Handler'는 요청이 Lambda로 들어올 때 처리할 handler를 지정해 주는 것입니다.
'index.handler'라고 되어 있는 이유는, 지금 생성중인 Lambda가 index.js가 되고 index.handler가 지금 생성중인 Lambda에 명시된 handler라고 하네요.

3-8. 설정들 Review합니다.

최종적으로 설정들을 Review합니다.
저도 아직 깊숙히 몰라서 설정하지 않은 항목들이 있는데, 나중에 깊숙히 알게 되면 다시 포스팅을 하도록 하겠습니다.
'Create function'을 클릭합니다.

3-9. 첫번째 API 테스트

생성하자마자 Lambda의 Trigger 탭 페이지가 보이고 누르고 싶게 생긴 URL이 있습니다.
저게 바로 방금 생성한 Lambda를 실행시킬 수 있는 REST API URL입니다.
한번 눌러보죠.

Forbidden 에러가 발생합니다.

에러가 발생한 이유는, 아까 'Security'를 'Open with access key'로 설정했는데 지금 링크를 누른건 아무 access key없이 요청이 보내졌기 때문에 발생한 에러입니다.
아래 그림에서 빨간색 네모칸이 쳐진 'Test'는 Lambda function 자체만 테스트 하는 것입니다. 그래서 아무 문제없이 정상적인 출력이 나오죠. 이게 출력이 잘 나온다고 API Gateway+Lambda가 정상작동한다고 생각하시면 안됩니다.
URL 밑에 'ANY'를 클릭해서 API Gateway 설정 페이지로 이동합니다.

3-10. API의 인증방법으로 Cognito를 설정합니다.

본 포스팅에서는 API를 호출할 수 있는 권한을 Cognito로 로그인한 유저에게만 주려고 합니다.
좀 더 자세히 말씀드리면, API를 정상적으로 호출하려면 Token이 필요하게 할 것이고, 이 Token은 Cognito를 이용한 로그인 시스템에서 유저가 로그인하면 발급 받는 idToken입니다.
(본 포스팅 상단의 Cognito 사용방법을 정리한 링크를 함께 보시면 좋을 것 같습니다.)
아래 그림에서 'Method Request'를 클릭합니다.

그러면 아래와 같은 설정화면이 나옵니다.
파란색 네모칸이 API 호출 권한에 대한 곳인데 여기서 'Authorization'과 'API Key Required'를 수정할 것입니다.

왼쪽의 'Authorizers'를 클릭합니다.
이동 된 페이지에서 상단의 'Create'-'Cognito User Pool Authorizer'를 선택합니다.

그러면 아래와 같은 설정 페이지가 나타나는데, 여기에 미리 만들어 놓은 User Pool의 정보를 기입하면 됩니다.

'Cognito region'은 User Pool을 만들어 놓은 리전을 선택합니다.
'Cognito user pool'은 미리 만들어 놓은 user pool을 선택합니다. 선택된 user pool에 있는 유저들만 지금 만들고 있는 API를 호출 할 수 있습니다.
'Authorizer name'은 적절히 원하는 이름으로 기입하시면 됩니다.
'Create'를 눌러서 Authorizer를 생성합니다.
만들면 아래 그림처럼 Authorizer가 하나 생성됩니다.

이제 만든 Authorizer를 API의 인증방법으로 선택하러 갑니다.
왼쪽에 있는 'Resources'를 누르고 'ANY'를 누르고 'Method Request'를 눌러서 아까 인증 설정 화면으로 이동합니다.

이제 'Authorization'의 목록을 보면 방금 생성한 Cognito user pool authorizer가 있습니다.
그것을 선택합니다.

그리고 'API Key Required'는 false로 선택합니다. 저는 처음에 Cognito에서 획득한 Token이 Key로 쓰인다고 생각해서 여기를 true로 했는데, 그랬더니 Cognito로 획득한 Token도 필요하고 API Gateway에서 만든 Key도 필요한 상황이 되었었습니다.
선택을 하고나면 네모칸의 체크모양 버튼을 꼭 눌러주셔야합니다.

API Gateway는 API에 변경사항이 발생하고나면 반드시 Deploy를 해야 반영됩니다. 이거때문에 안된다고 생각하고 난관을 겪는분들이 꽤 있다고 하네요.

'Deployment stage'는 prod로 합니다.(아직 심화가 아니라서 배포 단계를 나누진 않았습니다.)
'Deploy'해주세요.

3-11. 두번째 API 테스트

API도 설정했으니 테스트를 해봅시다.
최초 Lambda function의 기능이 위에서 언급한 것 처럼 body에 전해오는 key1의 값을 그대로 반환한다고 했습니다. 그러니 테스트를 위해서는 요청에 body가 껴야하고, 그러려면 POST 요청을 해야합니다.
그래서 테스트에 크롬 확장프로그램인 Postman을 이용합니다.
아래 그림처럼 요청방식을 POST로 선택해주시고, URL에는 API의 URL을 넣어주시고, Header에는 Cognito로 만든 로그인 시스템에서 로그인하여 획득한 idToken 값을 넣어줍니다.
그리고 body에는 key1, key2, key3를 json 형식으로 값과 함께 입력해줍니다.
그리고 'Send'를 눌러서 요청을 보내봅니다.

네, 에러가 발생합니다. Internal server error입니다. 이거는 Lambda function에서 난 에러입니다.

3-12. Lambda function 코드를 수정합니다.

만들어 놓은 Lambda function에 가서 아래 그림처럼 코드를 수정합니다.

주요 변경된 부분은 event에서 body의 내용을 추출하는 부분과 callback의 응답을 수정하는 부분입니다.
API Gateway의 API를 통해서 Lambda에 전달되는 요청은 body뿐만 아니라 다양한 이상한 값들과 함께 넘어갑니다. 그래서 body를 추출하려면 저렇게 해주셔야합니다.
그리고 API Gateway를 통해서 반환되는 응답에는 statusCode와 headers, body가 있어야 정상적인 응답이 보내집니다. headers는 상황에 따라서 적절히 더 추가하시면 됩니다.

3-13. 세번째 API 테스트

이제 마지막 테스트 입니다.
두번째 테스트와 동일하게 POST 요청을 보내봅니다.
짜잔~ 성공적으로 Request body의 첫번째 key인 key1의 value가 되돌아 왔습니다.

이 길고 긴 글을 읽어주셔서 너무 감사드립니다.
부디 이 입문자의 글이 다른 입문자 분들께 도움이 되었으면 좋겠습니다.
내용 중에 틀리거나 보완되야하거나 궁금한 내용은 댓글을 달아주시면 아는 지식 총 동원해서 포스팅을 수정하거나 답글을 달아드리겠습니다.
감사합니다