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가 되돌아 왔습니다.

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

댓글 1개:

  1. 훼북에서 보고 왔는데 잘 쓰셨네요. 서비스 기획에 도움이 많이 될 것 같습니다.

    답글삭제