API Gateway + Lambda

Server/AWS 2024. 12. 18. 21:39

API 가 딱 한 개만 필요하다면... 어떤 방법으로 api 서버를 구축하는 것이 좋을까. ec2 + framework 는 생각만 해도... 생각하고 싶지도 않고... 역시나  API Gateway + Lambda  이다. DB(Mysql) 에 insert 할 api 를 하나 만들어야 하는 상황인데... API Gateway 로 요청 받고 람다를 실행시켜서 DB에 insert 시킨 후 응답해 주면 완료...

 

 

1. API Gateway

 

  • API 타입 http-api, rest-api 중 요청 제한을 위해 적어도 api-key 정도는 설정하는 것이 좋겠다. http-api 는 api-key 를 지원하지 않으므로 rest-api 선택. (그 외에도 res-api 를 선택할 이유는 많지만, 정말 아~무것도 필요없다면 http-api 쓰면 됨.)
  • resource 에서 경로 만들고 요청 메서드 하나 만들고 api key 췍~ 스테이지 배포 후 API 키 / 실행 계획 작성 / 스테이지 연결
  • api 키는 프론트 요청 헤더(x-api-key) 에 담아서 전달 받으면 됨. 그렇지 않으면 요청 거부됨.'

 

{
    "message": "Forbidden"
}

 

 

 

2. Lambda Layer

 

  • 람다 함수 런타임은 간단하게 Nodejs 사용할 생각.
  • mysql 연결을 위해 mysql2 패키지를 설치해야 하는데 재사용을 위해 레이어를 하나 생성한다.
  • 호환 런타임 잘 선택하고, 아래 zip 파일 업로드. (기타 필요한 라이브러리도 설치)

 

$ mkdir nodejs
$ cd nodejs
$ npm init -y
$ npm install mysql2
$ zip -r mysql2-layer.zip .

 

 

nodejs 최신버전의 경우 index.mjs 파일이 생성되므로, ESM 모듈 사용하려면, 압축하기 전에 package.json 에 아래 타입을 명시한다.

 

{
    "type": "module"
}

 

 

require is not defined in ES module scope, you can use import instead 에러 시 참고.

 

 

3. Lambda Function

 

nodejs 람다 함수를 하나 생성하고, 코드 가장 하단 설정에서 위에 업로드 한 layer 를 선택한다. index.mjs 파일 작성 후 배포.

 

import mysql from 'mysql2/promise';

const pool = mysql.createPool({
  host: 'host',
  user: 'user',
  password: 'password',
  database: 'database',
  port: 'port'
});

export const handler = async (event) => {

  const { id, name } = JSON.parse(event.body);

  try { 
    const query = 'INSERT INTO user (id, name) VALUES (?, ?)';

    const [results] = await pool.execute(query, [id, name]);
    return {
      statusCode: 200,
      body: JSON.stringify({ code: 200, message: 'ok', data: results })
    };
  } catch (err) {
    return {
      statusCode: 200,
      body: JSON.stringify({ code: 500, message: 'error: db insert', error: err.message })
    };
  }
};

 

 

4. API Gateway - Lambda 연결

 

API Gateway 해당 리소스의 통합 요청에서 생성한 람다 함수를 연결한다. request payload 를 람다 함수에 전달하기 위해  [Lambda 프록시 통합] 활성화 . 설정 후 [API 배포].

 

 

5. 테스트

 

postman 에서 header 에 api 키를 담아 stage url/resource 경로로 api 테스트를 진행한다.

 

{
    "code": 200
    "message": "ok",
    "data": {
        "fieldCount": 0,
        "affectedRows": 1,
        "insertId": 0,
        "info": "",
        "serverStatus": 2,
        "warningStatus": 0,
        "changedRows": 0
    }
}

 

 

6. 디버깅

 

만약 정상적인 응답을 받지 못했다면, 스테이지에서 cloudwatch logs 를 켜고, 로그를 확인한다. 처음 실행할 때는 cloudwatch 로깅에 대한 role 이 필요하다. IAM 에서 AmazonAPIGatewayPushToCloudWatchLogs 정책으로 role 하나 만들고, API Gateway 좌측 메뉴 설정에서 해당 role 선택.

 

 

7. 게이트웨이 응답

 

필요시 [게이트웨이 응답] 메뉴에서 request 에러시 응답값을 커스텀 할 수 있다.

 

 

8. CORS error

 

Access to fetch at 'https://11111111.execute-api.ap-northeast-2.amazonaws.com/dev/request' from origin 'http://localhost:8888' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

 

실전은 다르다. 매번 ok 사인 주는 postman 은 실전과 다르다. 프로젝트 할 때마다 괴롭히는 cors 에러... 메서드 선택 후 CORS 를 활성화 시키면 되구용...

 

 

 

 프록시 통합(proxy integrations)  이 설정되었기 때문에, 람다에서의 응답 헤더가 적용된다. 하여 람다에 적절한 응답 헤더가 추가되어야 한다.

 

return {
  statusCode: 200,
  headers: {
    "Access-Control-Allow-Headers" : "Content-Type,X-Api-Key",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "OPTIONS"
  },
  body: JSON.stringify({ code: 200, message: 'ok', data: results })
};

 

. 끝 .


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,