Amazon Web Service

AWS 서버리스 lambda API 개발하고 Dynamo DB에 저장하기

간다12 2024. 11. 23. 14:30

AWS 서버리스로 API gateway Lambda 연해서 API 개발하고 Dynamo DB에 개발해보자.

 

DynamoDB는 AWS(Amazon Web Services)에서 제공하는 완전 관리형 NoSQL 데이터베이스 서비스입니다. 낮은 지연 시간, 높은 성능, 확장성을 갖춘 데이터베이스로 설계되어 대규모 애플리케이션에서 자주 사용됩니다.


DynamoDB의 특징

  1. 완전 관리형
    • 서버 관리가 필요 없습니다. AWS가 자동으로 프로비저닝, 배포, 유지보수, 보안 패치를 처리합니다.
  2. NoSQL
    • 관계형 데이터베이스(RDBMS)와 달리 DynamoDB는 스키마가 고정되지 않은 유연한 데이터 모델을 사용합니다.
    • JSON 형식의 데이터를 테이블에 저장하며, 테이블은 키-값(Key-Value) 또는 문서(Document) 모델로 작동합니다.
  3. 높은 확장성
    • 자동으로 데이터를 분산 처리하여 읽기/쓰기 처리량을 동적으로 확장할 수 있습니다.
    • 트래픽이 급증하는 환경에서도 안정적으로 작동합니다.
  4. 낮은 지연 시간
    • 초당 수백만 건의 요청을 처리하며, 10밀리초 미만의 일관된 응답 시간을 제공합니다.
  5. 유연한 요금 구조
    • 사용한 만큼만 비용을 지불합니다.
    • 온디맨드(On-Demand) 또는 프로비저닝 모드(Provisioned Mode) 중 선택 가능.

 

  • 먼저, Nosql기반인 Dynamo DB를 생성해보자.

  • Dynamo DB에 연계하기위해서 Lambda를 생성해보자.
  • Node.js로 코드를 작성하고 역할을 Dynamo DB와 연결할거기 때문에 단순 마이크로서비스 권한으로 세팅했다.

 

  • HTTP Header 세팅을 해주었고 DynamoDB에 저장할 수 있도록 코드를 작성해보자.
  • Cors를 설정해서 접근할 수 있도록 세팅하자.
  • HTTP 메소드는 DynamoDB에 PUT, DELETE, GET 접근할 수 있도록 했다.
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  ScanCommand,
  PutCommand,
  GetCommand,
  DeleteCommand,
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({});
const dynamo = DynamoDBDocumentClient.from(client);
const tableName = "";
const allowedOrigins = [];

export const handler = async (event, context) => {
  console.log("Event: ", JSON.stringify(event, null, 2));
  let body;
  let statusCode = 200;
  const headers = {
    "Content-Type": "application/json",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Credentials": "true"
  };

  // CORS Preflight 요청 처리
  if (event.httpMethod === "OPTIONS") {
    const origin = event.headers.origin;
    console.log("OPTIONS request from origin: ", origin);

    // 요청된 origin이 허용된 origin 목록에 있는지 체크
    if (allowedOrigins.includes(origin)) {
      headers["Access-Control-Allow-Origin"] = origin;
    } else {
      headers["Access-Control-Allow-Origin"] = allowedOrigins[1];  // 기본값 설정
    }

    console.log("CORS headers set for OPTIONS request: ", headers);

    return {
      statusCode: 200,
      body: "",
      headers: headers, // OPTIONS 응답에 필요한 CORS 헤더 설정
    };
  }

  // `OPTIONS` 요청 외에도 실제 요청에 대해서도 Access-Control-Allow-Origin 설정
  const origin = event.headers.origin;
  console.log("Request from origin: ", origin);
  if (allowedOrigins.includes(origin)) {
    headers["Access-Control-Allow-Origin"] = origin;
  } else {
    headers["Access-Control-Allow-Origin"] = allowedOrigins[1];  // 기본값 설정
  }

  console.log("CORS headers set for request: ", headers);

  try {
    switch (event.routeKey) {
      case "DELETE /items/{id}":
        console.log("DELETE request for id: ", event.pathParameters.id);
        await dynamo.send(
          new DeleteCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = `Deleted item ${event.pathParameters.id}`;
        break;
      case "GET /items/{id}":
        console.log("GET request for id: ", event.pathParameters.id);
        body = await dynamo.send(
          new GetCommand({
            TableName: tableName,
            Key: {
              id: event.pathParameters.id,
            },
          })
        );
        body = body.Item;
        break;
      case "GET /items":
        console.log("GET request for all items");
        body = await dynamo.send(
          new ScanCommand({ TableName: tableName })
        );
        body = body.Items;
        break;
      case "PUT /items":
        console.log("PUT request with body: ", event.body);
        let requestJSON = JSON.parse(event.body);
        await dynamo.send(
          new PutCommand({
            TableName: tableName,
            Item: {
              id: requestJSON.id,
              price: requestJSON.price,
              name: requestJSON.name,
              insertTime: new Date().toISOString(),
            },
          })
        );
        body = `Put item ${requestJSON.id}`;
        break;
      default:
        throw new Error(`Unsupported route: "${event.routeKey}"`);
    }
  } catch (err) {
    statusCode = 400;
    body = err.message;
    console.error("Error: ", err);
  } finally {
    body = JSON.stringify(body);
    console.log("Response body: ", body);
  }

  return {
    statusCode,
    body,
    headers,
  };
};

 

  • API gateway에 이동해서 HTTP API를 개발해보자.

  • 통합에서 Lambda를 선택하고 생성한 Lambda를 선택하자.

  • 람다에 연결할 리소스 경로를 생성해보자.

  • API gateway 통합에서 경로가 Lambda와 연결된 것을 확인할 수 있다.

  • Cors로 이동해서 허용 Origin과 Header Method 등을 세팅해보자.

  • API로 이동해서 기본 엔드포인트로 HTTP 메소드 전송을 해보자!

  • Put / Get 메소드로 전송하면 정상적으로 상태코드 200을 받을 것을 확인할 수 있다.

  • Dynamo DB에서도 저장된 항목을 확인 할 수 있다.

  • local로 올린 vue.js에서도 Api 통신이 되는 것을 확인 할 수 있다.
  • local서버로 전송할 때는 Cors에 주의하기로 하자. 
    • PUT 전송할 때는 Options 메소드를 보내고 정상적으로 통신되어야 PUT전송을 한다. 그렇기 때문에 API GATEWAY에 설정에서 HTTP OPTIONS 메소드도 ALlow해준다.
    • Domain ALlow도 localhost:8080을 열어두고 배포도 할것이라면 배포할 도메인도 세팅해주면 된다.

반응형