민프

[AWS] API-Gateway + Lambda를 이용하여 S3에 이미지 업로드를 해보자 본문

DevOps/[AWS]

[AWS] API-Gateway + Lambda를 이용하여 S3에 이미지 업로드를 해보자

민프야 2025. 6. 10. 19:20

이번 글에서는 API Gateway + Lambda + S3를 활용하여 사용자가 이미지를 업로드하면 Lambda가 이를 S3 버킷에 저장하는 아키텍쳐를 구축한 과정을 알려드리겠습니다

 


실습 과정

  1. 클라이언트가 multipart/form-data 형식으로 이미지를 POST로 전송
  2. API Gateway가 요청을 받아 Lambda를 호출
  3. Lambda는 S3 버킷에 이미지를 저장
  4. 저장 후 결과를 반환 (성공/실패 여부)

구현 과정

1. S3 버킷 생성


2. Lambda 함수 구성 (Python 3.11)

 

python에서 multipart/form-data를 받기 위하여 toolbelt-layer를 계층으로 삽입하였습니다.

// Python디렉토리 생성 및 패키지 설치
mkdir -p python
pip install requests-toolbelt -t python

// 압축
zip -r9 toolbelt-layer.zip python

from requests_toolbelt.multipart import decoder

def lambda_handler(event, context):
    import boto3
    import base64
    import uuid
    from requests_toolbelt.multipart import decoder

    bucket = '버킷 이름을 넣으시면 됩니다.'
    file_name = f"menu/{uuid.uuid4().hex}.jpg" // 폴더 이름 및 파일이름 지정
    
    body = base64.b64decode(event["body"])
    content_type = event["headers"].get("Content-Type") or event["headers"].get("content-type")

    multipart_data = decoder.MultipartDecoder(body, content_type)

    for part in multipart_data.parts:
        if b'image' in part.headers.get(b'Content-Type', b''):
            s3 = boto3.client('s3')
            s3.put_object(
                Bucket=bucket,
                Key=file_name,
                Body=part.content,
                ContentType='image/jpeg'
            )
            return {
                "statusCode": 200,
                "body": f"Uploaded as {file_name}"
            }

    return {
        "statusCode": 400,
        "body": "No image found in multipart data"
    }

toolbelt-layer.zip
1.21MB

 


3. API-gateway 생성 및 설정

-1. 리소스 생성

 

-2. 메서드 생성

위에서 만든 Lambda를 연결해주세요.

 

-3. 이진 미디어 유형 추가

API를 선택한 후 -> API 설정 -> 미디어 유형 관리에서 'multipart/form-data'추가

 

-4. 리소스 설정

 

리소스 설정을 하기에 앞서 위 사진의 각 단계가 어떤 것들을 의미하는지부터 알아보겠습니다.

 

1. 메서드 요청 (Method Request)

  • 클라이언트가 API Gateway에 보내는 요청을 다룹니다.
  • 여기에서 설정 가능한 것들
    • HTTP 메서드 (GET, POST 등)
    • URL 경로 파라미터, 쿼리 스트링, 헤더
    • IAM 인증, API Key, CORS 설정
    • 예를 들어서)
      /menu-ai?type=jpeg의 요청에서 type을 파라미터로 받을지 여부 등을 설정

 

 

2. 통합 요청 (Integration Request)

  • API Gateway가 백엔드 서비스(Lambda 등)로 요청을 보내기 전 처리하는 단계입니다.
  • 실제로는 여기서 Lambda에 전달할 payload 가공(매핑), 포맷 설정, 이진 처리를 합니다.
    예를 들어서) form-data로 받은 이미지를 base64로 인코딩하거나, S3에서 쓸 key 이름으로 변환하는 작업

저는 여기서 매핑 템플릿을 넣었습니다. 

아래 템플릿은 multipart/form-data로 업로드된 이진 데이터를 API Gateway가 Lambda가 이해할 수 있는 JSON 형태로 변환해주는 역할을 합니다.

 

#set($inputRoot = $input.path('$'))
{
    "body": "$input.body", -> 클라이언트로부터 받은 실제 body 내용(이진)
    "isBase64Encoded": true, -> Lambda에서 base64로 디코딩해서 파일로 처리할 수 있게 명시
    "headers": { -> 요청 헤더들을 모두 Lambda에 넘겨줌 (예: Content-Type, boundary 등)
        #foreach($header in $input.params().header.keySet()) -> 전체 헤더를 동적으로 key:value 쌍으로 만들어 줌
        "$header": "$util.escapeJavaScript($input.params().header.get($header))"
        #if($foreach.hasNext),#end 
        #end
    }
}

 

이렇게 매핑 템플릿을 만들게 되면 Lambda함수에서는 아래와 같이 받게 됨으로써 base64.b64decode(event['body'])로 파일을 복원

할 수 있게 됩니다.

 

{
  "body": "base64로 인코딩된 이미지 본문",
  "isBase64Encoded": true,
  "headers": {
    "Content-Type": "multipart/form-data; boundary=..."
  }
}



3. Lambda 통합 (Integration Target)

  • 실제 Lambda 함수 또는 HTTP, VPC 등 연결된 백엔드 서비스가 실행되는 지점입니다.
  • 위에서 준비한 payload를 기반으로 Lambda가 호출됩니다.

 

4. 통합 응답 (Integration Response)

  • Lambda의 실행 결과를 받아 API Gateway가 해석하는 단계입니다.
  • 주로 여기서 상태코드 매핑 (200, 500 등), 응답 body 가공, 에러 포맷 등을 처리합니다.
    예를 들어서) Lambda가 { statusCode: 500 }을 반환했을 때 이를 클라이언트에게 어떻게 보여줄지 설정 가능

5. 메서드 응답 (Method Response)

  • API Gateway가 클라이언트에게 최종적으로 전달할 응답을 구성하는 단계입니다.
  • 클라이언트에 보낼 HTTP 상태코드, 헤더, JSON 스키마 구조 등을 지정할 수 있습니다.
    예를 들어서) 응답 header에 Content-Type: application/json을 넣거나, CORS 허용 헤더를 설정하는 곳

저는 아래와 같이 하였습니다.

 

-5. API 배포 및 스테이지 CloudWatch 설정

API 배포를 하시면 스테이지가 생성되는데 이 부분에서 로그들을 추적하고 싶으시다면

'스테이지 -> 로그 및 추적 -> 편집' 에 차례대로 접근하시면 되는데

관련 권한 에러가 나올 수 있으니 나오는 권한을 IAM에서 추가해주시면 됩니다. 


예시 정리

자 그럼 위 설정에 대한 예시를 다시 한번 정리해보겠습니다.

POST /menu-ai로 이미지 업로드 요청 시

  1. 메서드 요청: 사용자 요청을 받아들임 (form-data, header 등)
  2. 통합 요청: 요청 body를 Lambda가 이해할 수 있는 JSON 형식으로 변환
  3. Lambda 통합: Lambda 함수 실행, S3에 이미지 저장
  4. 통합 응답: Lambda 응답의 statusCode, body를 분해 및 가공
  5. 메서드 응답: 최종 응답 구조로 만들어 사용자에게 반환

결과

 

postman으로 요청했고, s3에 잘 저장된 것을 확인하실 수 있습니다.

Comments