Use Cases

Claude Code × AWS API Gateway 완전 가이드 | REST API 설계부터 배포 자동화까지

Claude Code로 AWS API Gateway 엔드포인트를 자동 설계. 리소스 설계·Lambda 통합·인증·배포까지, Masa의 업무 경험을 바탕으로 실례 코드로 해설.

API Gateway 설계 공수가 1/3로 줄어든 이야기

claudecode-lab.com을 운영하는 Masa입니다. 프리랜서 백엔드 개발을 하던 시절, AWS API Gateway 설계와 구현은 “은근히 시간이 걸리는 작업”의 대표였습니다. 엔드포인트 설계서를 작성하고, CloudFormation 템플릿으로 옮기고, Lambda 통합 설정을 수동으로 입력하고, CORS를 설정하고…매번 같은 실수를 반복했습니다.

전환점은 6개월 전, Claude Code에 “이 유스케이스를 바탕으로 REST API를 설계하고 CDK로 구현해줘”라고 던져봤을 때입니다. 놀라울 만큼 실용적인 구성이 나왔고, 그 이후로 API Gateway 관련 구현 공수가 1/3로 줄었습니다.

CORS 설정 누락, Lambda 권한 오류, 타임아웃 29초 제한의 함정도 “Claude Code가 처음부터 주의해줄 수 있게 된” 이후로 리뷰에서 지적받는 횟수도 크게 줄었습니다.


왜 API Gateway 설계에 Claude Code가 적합한가

API Gateway 설계에는 “전문 지식은 필요 없지만 반복 작업이 많다”는 특징이 있습니다.

  • 엔드포인트 명명 규칙 (명사 복수형, 계층 구조)
  • HTTP 메서드 사용법 (GET/POST/PUT/PATCH/DELETE)
  • 요청/응답 스키마 정의
  • Lambda 통합의 경로 변수 매핑
  • CORS 헤더 설정 (매번 잊어버림)
  • 스테이지 변수 관리 (dev/staging/prod)

Step 1: REST API 엔드포인트 설계를 Claude Code에 의뢰

프롬프트 예시

아래 유스케이스를 바탕으로 REST API의 엔드포인트 설계서를 만들어줘.

유스케이스:
- 태스크 관리 앱 (사용자가 프로젝트와 태스크를 관리)
- 사용자 인증 있음 (Cognito)
- 프로젝트에 멤버를 추가 가능
- 태스크에 댓글과 파일 첨부 가능

출력 형식:
- 엔드포인트 목록 (메서드·경로·설명)
- 요청/응답 JSON 스키마
- 인증이 필요한 엔드포인트 명시
- REST 원칙 위반 사항이 있으면 지적

Step 2: Lambda 통합 설정 자동 생성

생성된 CDK 스택 (발췌)

import * as cdk from "aws-cdk-lib";
import * as apigateway from "aws-cdk-lib/aws-apigateway";
import * as nodejs from "aws-cdk-lib/aws-lambda-nodejs";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";

export class TaskApiStack extends cdk.Stack {
  public readonly api: apigateway.RestApi;

  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // ===== Lambda 함수 팩토리 =====
    const createLambda = (name: string, handler: string) =>
      new nodejs.NodejsFunction(this, name, {
        entry: `src/handlers/${handler}.ts`,
        handler: "handler",
        runtime: lambda.Runtime.NODEJS_20_X,
        timeout: cdk.Duration.seconds(29), // API Gateway 최대 타임아웃
        memorySize: 256,
        bundling: {
          minify: true,
          sourceMap: true,
          externalModules: ["@aws-sdk/*"],
        },
      });

    const listProjectsFn = createLambda("ListProjects", "projects/list");
    const createProjectFn = createLambda("CreateProject", "projects/create");
    const getProjectFn = createLambda("GetProject", "projects/get");
    const updateProjectFn = createLambda("UpdateProject", "projects/update");
    const deleteProjectFn = createLambda("DeleteProject", "projects/delete");

    // ===== REST API 정의 =====
    this.api = new apigateway.RestApi(this, "TaskApi", {
      restApiName: "task-management-api",
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS, // 프로덕션에서는 제한할 것
        allowMethods: apigateway.Cors.ALL_METHODS,
        allowHeaders: ["Content-Type", "Authorization", "X-Api-Key"],
      },
      deployOptions: {
        stageName: "v1",
        loggingLevel: apigateway.MethodLoggingLevel.INFO,
        dataTraceEnabled: false,
      },
    });

    // ===== 리소스 & 메서드 정의 =====
    const projects = this.api.root.addResource("projects");
    projects.addMethod("GET", new apigateway.LambdaIntegration(listProjectsFn));
    projects.addMethod("POST", new apigateway.LambdaIntegration(createProjectFn));

    const project = projects.addResource("{id}");
    project.addMethod("GET", new apigateway.LambdaIntegration(getProjectFn));
    project.addMethod("PUT", new apigateway.LambdaIntegration(updateProjectFn));
    project.addMethod("DELETE", new apigateway.LambdaIntegration(deleteProjectFn));

    new cdk.CfnOutput(this, "ApiUrl", {
      value: this.api.url,
      description: "API Gateway URL",
    });
  }
}

Step 3: 인증 설정 (Cognito / Lambda Authorizer / API Key)

패턴 1: Cognito User Pool Authorizer (BtoC)

import * as cognito from "aws-cdk-lib/aws-cognito";

const userPool = new cognito.UserPool(this, "UserPool", {
  userPoolName: "task-app-users",
  selfSignUpEnabled: true,
  signInAliases: { email: true },
  passwordPolicy: {
    minLength: 8,
    requireLowercase: true,
    requireUppercase: true,
    requireDigits: true,
  },
});

const cognitoAuthorizer = new apigateway.CognitoUserPoolsAuthorizer(
  this,
  "CognitoAuthorizer",
  {
    cognitoUserPools: [userPool],
    identitySource: "method.request.header.Authorization",
    resultsCacheTtl: cdk.Duration.minutes(5), // 비용 절감을 위한 캐시
  }
);

projects.addMethod("GET", new apigateway.LambdaIntegration(listProjectsFn), {
  authorizer: cognitoAuthorizer,
  authorizationType: apigateway.AuthorizationType.COGNITO,
});

패턴 2: Lambda Authorizer

// src/handlers/auth/authorizer.ts
import {
  APIGatewayAuthorizerResult,
  APIGatewayTokenAuthorizerHandler,
} from "aws-lambda";
import * as jwt from "jsonwebtoken";

export const handler: APIGatewayTokenAuthorizerHandler = async (event) => {
  const token = event.authorizationToken.replace("Bearer ", "");

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as {
      sub: string;
      email: string;
      role: string;
    };

    return generatePolicy(decoded.sub, "Allow", event.methodArn, {
      userId: decoded.sub,
      email: decoded.email,
      role: decoded.role,
    });
  } catch {
    throw new Error("Unauthorized"); // 401 반환
  }
};

function generatePolicy(
  principalId: string,
  effect: "Allow" | "Deny",
  resource: string,
  context?: Record<string, string>
): APIGatewayAuthorizerResult {
  return {
    principalId,
    policyDocument: {
      Version: "2012-10-17",
      Statement: [
        {
          Action: "execute-api:Invoke",
          Effect: effect,
          // 와일드카드로 캐시 효과 극대화
          Resource: resource.replace(/\/[^/]+\/[^/]+$/, "/*/*"),
        },
      ],
    },
    context,
  };
}

Step 4: 스테이지 관리 (dev/staging/prod)

// lib/config.ts
export type Stage = "dev" | "staging" | "prod";

export const stageConfig: Record<Stage, {
  throttleRateLimit: number;
  corsOrigins: string[];
  enableDataTrace: boolean;
}> = {
  dev: {
    throttleRateLimit: 10,
    corsOrigins: ["http://localhost:3000"],
    enableDataTrace: true,
  },
  staging: {
    throttleRateLimit: 50,
    corsOrigins: ["https://staging.example.com"],
    enableDataTrace: false,
  },
  prod: {
    throttleRateLimit: 1000,
    corsOrigins: ["https://example.com"],
    enableDataTrace: false,
  },
};
# 개발 환경 배포
CDK_ENV=dev npx cdk deploy Api-dev --require-approval never

# 스테이징
CDK_ENV=staging npx cdk deploy Api-staging

# 프로덕션 (변경 확인 있음)
CDK_ENV=prod npx cdk deploy Api-prod

함정 4선

함정 1: CORS 설정 누락 (가장 빈번)

// ❌ 불충분
defaultCorsPreflightOptions: {
  allowOrigins: apigateway.Cors.ALL_ORIGINS,
}

// ✅ Lambda 응답에도 반드시 CORS 헤더 추가
return {
  statusCode: 200,
  headers: {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "https://example.com",
    "Access-Control-Allow-Credentials": "true",
  },
  body: JSON.stringify(data),
};

함정 2: Lambda 실행 권한 설정 누락

listProjectsFn.addPermission("ApiGatewayInvoke", {
  principal: new iam.ServicePrincipal("apigateway.amazonaws.com"),
  sourceArn: this.api.arnForExecuteApi("GET", "/projects", "v1"),
});

함정 3: 29초 타임아웃 제한

// ✅ 비동기 처리 패턴: 즉시 job ID 반환 후 폴링
export const startExport: APIGatewayProxyHandler = async (event) => {
  const jobId = crypto.randomUUID();

  await sqsClient.send(
    new SendMessageCommand({
      QueueUrl: process.env.JOB_QUEUE_URL!,
      MessageBody: JSON.stringify({ jobId, params: JSON.parse(event.body!) }),
    })
  );

  return {
    statusCode: 202,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ jobId, status: "processing" }),
  };
};

함정 4: Lambda의 요청 본문 변환

// ✅ 항상 명시적으로 proxy: true 설정
project.addMethod(
  "POST",
  new apigateway.LambdaIntegration(createProjectFn, {
    proxy: true,
  })
);

정리 테이블

작업Claude Code 활용 포인트난이도
REST API 설계유스케이스에서 설계서 자동 생성, REST 원칙 체크낮음
Lambda 통합 CDK프록시 통합·리소스 정의를 일괄 생성낮음
Cognito 인증User Pool·Authorizer·클라이언트 설정 생성중간
Lambda AuthorizerJWT 검증·정책 생성 구현중간
스테이지 관리환경별 설정 분리·배포 명령 생성중간
비동기 처리SQS 연동·폴링 패턴 설계높음
CORS 설정Lambda 측 헤더 설정을 누락 없이 생성낮음

이 글에서 소개한 내용을 업무 프로젝트에서 실천한 결과: API Gateway 설계~CDK 배포까지의 공수가 기존 3일→1일로 단축되었습니다. 특히 Cognito Authorizer 주변 구현은 이전에는 매번 AWS 문서를 1시간 이상 읽던 부분이, Claude Code에의 프롬프트 하나로 해결되게 되었습니다.


관련 기사

참고 자료

#claude-code #aws #api-gateway #lambda #typescript #rest-api

Claude Code 워크플로우를 한 단계 업그레이드하세요

지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.

무료 제공

무료 PDF: 5분 완성 Claude Code 치트시트

이메일 주소만 등록하시면 A4 한 장짜리 치트시트 PDF를 즉시 보내드립니다.

개인정보는 엄격하게 관리하며 스팸은 보내지 않습니다.

Masa

이 글을 작성한 사람

Masa

Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.