코딩스토리

AWS Lambda와 API Gateway 사용하여 메일링 코드 개발 본문

프로젝트

AWS Lambda와 API Gateway 사용하여 메일링 코드 개발

kimtaehyun98 2022. 7. 3. 20:34

프로젝트를 진행하면서 Air Table을 사용하게 되었다.

 

Air Table 홈페이지

https://www.airtable.com/

 

Airtable | Everyone's app platform

Airtable is a low-code platform for building collaborative apps. Customize your workflow, collaborate, and achieve ambitious outcomes. Get started for free.

www.airtable.com

 

다양한 용도가 있지만 우리 팀에서 쓰려는 용도는 "사용자의 건의사항을 저장하고 관리하는 DB"이다.

 

원래라면 DB와 API 서버가 필요하겠지만, Air Table은 자체적으로 CRUD API를 제공한다.

(이게 굉장히 별 거 아닌 것 같지만 서버가 필요 없다는 강력한 장점을 가지고 있는 것이다! 🤔)

따라서 저비용 설계를 위해서는 Air Table은 매우 적합한 Tool이라고 추천받아서 사용하게 되었다.

 

해당 포스팅은 Air Table에 관한 포스팅은 아니니 이쯤에서 넘어가자.

(원랜 Air Table에 대한 포스팅부터 하려고 했는데 막히는 부분이 있어서.. 조만간 올릴 예정입니다..!)

 

결론적으로 Air Table에서 제공하는 API를 사용하여 Air Table에 바로 데이터를 Create 할 수 있었다.

 

하지만 문제는 API를 호출하기 위해서는  Private Token값이 필요하다는 것이었다.

즉, 이 API를 사용자가 호출하게 해야 되는데 그러려면 사용자에게 나의 Private Token값을 넘겨야 된다는 것이다..

 

그래서! 우리는 API를 한 단계 감싸줌으로써 해당 문제를 해결하였다.

 

즉, 사용자가 호출하는 API 안에 로직으로 Token을 사용하는 CRUD API를 호출하면, 사용자에게 Token을 노출하지 않아도 된다.

 

이러한 경우에 쉽고 빠르게 사용할 수 있는 것이 AWS Lambda와 API Gateway를 사용하는 것이다.

 

말로 설명하려고 하니 어려운데.. 아키텍쳐는 아래와 같다.

 

 

너무 간단해서 설명이 필요없을 것 같긴 한데.. 이런 식으로 구성된다. 😉

 

AWS Lambda  함수 생성 및 테스트

 

먼저 람다 함수를 생성한다.

런타임 환경은 말 그대로 람다 함수가 실행될 환경이다.

 

나는 Node.js를 사용하였다.

 

잠시 람다 함수에 대해서 설명해보면, Serverless 환경이란 말은 말 그대로 유지되고 있는 서버가 없다는 말이다.

 

즉, 람다 함수는 어떠한 트리거에 의해 호출 되기 전까지는 말 그대로 작성된 코드에 불과하다.

 

하지만 어느 순간 호출되었을 시, 해당 함수를 실행시킨다.

 

이때 뭘 사용해서 런타임을 가져갈 것인지를 고르라는 것이고, 즉 쉽게 말하면 Node.js 서버를 쓸 건지 Spring 서버를 쓸 건지 고르라는 것이다.

 

많은 런타임 환경을 지원하고 있지만, Node.js를 권장하기도 하고 부팅 시간이 짧아서 해당 환경을 선택하였다.

 

람다 함수를 생성하면 위와 같은 코드들을 볼 수 있다.

 

이제 말 그대로 내가 실행하고 싶은 로직을 함수 안에 구현한다고 생각하고 구현하면 된다.

 

그렇게 해서 코드를 다 짰다고 가정해보자. 

내가 짠 코드는 아래와 같다.

// axios Module
const axios = require('axios');

exports.handler = async (event) => {
    // Air Table API Key
    let token = "TokenValue";
    
    let url = "https://api.airtable.com";
    
    // Request Info (Music)
    let musicName = event.fields.MusicName;
    let musicSinger = event.fields.MusicSinger;
    let musicNumberTJ = event.fields.MusicNumberTJ;
    let musicNumberKY = event.fields.MusicNumberKY;
    
    // Status
    let resStatusCode = "";
    let resStatusMessage = "";
    
    const config = {
        headers: { Authorization: `Bearer ${token}` }
    };

    const bodyParameters = {
       fields: {
                    MusicName: musicName,
                    MusicSinger: musicSinger,
                    MusicNumberTJ: musicNumberTJ,
                    MusicNumberKY: musicNumberKY,
                    Calls: 0,
                    Status: "To Do"
                },
        typecast: true
    };
    
    // Function : Create Row in Air Table
    const createRow = async() => {
        return await axios
            .post(
                url,
                bodyParameters,
                config
            )
            .then((res) => {
                resStatusCode = res.status;
                resStatusMessage = res.statusText;
            })
            .catch(error => {
            if (error.response) {
                console.log("error!!");
            }
          });
    };
    
  
    // Call createRow Function
    await createRow();
    
    // response
    const response = {
        statusCode: resStatusCode,
        body: JSON.stringify(resStatusMessage),
    };
    
    return response;
};

 

앞서 말했던 Air Table을 Api를 호출하고, 상태를 반환하는 코드이다.

Node가 내 주 기술스택이 아니기에.. 코드 퀄리티는..ㅎ 🙃

그럼 이제 해당 코드가 제대로 짜 졌는지, 테스트를 수행해야 한다.

 

테스트 구성하기

 

테스트 이벤트란 말 그대로 API에 Request를 보내는 것처럼 테스트하는 것이다.

 

테스트 설정이 끝나면 테스트 실행 버튼을 누른다.

이때 반드시 Deploy 버튼을 눌러야 수정된 코드가 반영된다!

(안 그러면 나처럼 Response Code 200을 쉼 없이 받을 수 있다.)

 

그렇게 deploy 후 테스트 해보면 Axios 에러가 난다. (코드에 Axios 코드가 있는 분들이라면)

{
  "errorType": "Runtime.ImportModuleError",
  "errorMessage": "Error: Cannot find module 'axios'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/index.mjs",
  "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module 'axios'",
    "Require stack:",
    "- /var/task/index.js",
    "- /var/runtime/index.mjs",
    "    at _loadUserApp (file:///var/runtime/index.mjs:726:17)",
    "    at async Object.module.exports.load (file:///var/runtime/index.mjs:741:21)",
    "    at async file:///var/runtime/index.mjs:781:15",
    "    at async file:///var/runtime/index.mjs:4:1"
  ]
}

 

이거 옛날에 분명 겪었었는데.. 기억이 날랑 말랑.. 하다가..!

Node.js에서 Axios 모듈을 사용하려면 Node modules가 필요하다는 것이 생각났다.

 

원래는 layer 추가해야 되고 등등.. 굉장히 복잡한 작업을 해야 한다.

 

Layer를 설정하는 방법은 아래 링크에서 잘 설명하고 있다.

https://medium.com/signal9/aws-lambda-layer-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-node-js-8c299a1d0a6f

 

AWS lambda layer 사용하기 (node.js)

AWS Lambda 에서는 layer라는 기능을 제공한다. 소스코드나 외부라이브러리들을 layer 라는 단위로 모듈화 하고 이를 여러 lambda 함수에서 사용할 수 있도록 해준다.

medium.com

 

잘 설명하고 있는데,

너무 귀찮다..

 

왜냐면 더 좋은 방법이 있다 ㅎ

 

"zip 파일 만들어서 올리기"

 

단 index.js로 만들고 npm install axios를 로컬에서 진행하여서 node_modules 생겨야 함!

 

그럼 해결됨!

 

 

물론 다른 에러가 뜨겠지만 😡

 

이걸 선견지명하고 알려준 사람이 팀원 중에 있었는데.. 진짜 그는 신인가?

 

이렇게 하면 axios 에러 해결하고 다른 에러도 해결하면 성공적으로 Lambda함수 테스트 완료!

(참고로 구성-> 일반 구성 -> 편집 -> 제한시간 늘려주는 게 좋음!

왜냐하면 Lambda 실행 제한시간이 짧을 때 로직 실행시간이 길어지면 에러로 처리해버린다!)

 

 

이제 Lambda를 잘 개발했음을 확인했으니 트리거를 생성하여 호출될 수 있도록 만들어주어야 한다.

 

즉, API Gateway를 사용하여 다른 사람도 호출할 수 있도록 하여야 한다.

 

 

API Gateway 만들었으면 들어가서 POST Method로 변경

 

이제 [작업]-> [CORS 활성화]를 꼭 해줘야 한다!!!

 

이제 설정이 끝났으면, [API 배포] 버튼을 눌러 배포를 진행한다.

 

 

이 과정이 끝나고 다시 람다 페이지로 돌아가 보면 트리거 생성되어 있음!

 

트리거의 api를 postman에서 호출하면 성공!

 

 

이렇게 빠르고 간단하게 API를 만들 수 있다.

 

Serverless의 장점을 적절하게 이용하였기에 빠르게 구현할 수 있었고, 가장 중요한 점은 과금 이슈가 생기지 않는다는 것이다.

(Lambda가 무료 호출 횟수가 어마 무시하기 때문에 크게 걱정하지 않아도 된다.)

 

만약 서버를 직접 구현하고 API를 만들고 EC2에 올려서 배포하고 이랬으면... 생각만 해도 쉽지 않다.

Comments