함수 프록시 통합 REST API 생성하기
함수 프록시 통합 REST API 생성하기
이 코드 예제에서는 Lambda 프록시 통합을 사용해 REST API를 생성·배포하는 방법을 보여드려요.
출처: 문서
본문
- Lambda 실행용 IAM 역할 생성
- Lambda 함수 생성 및 배포
- REST API 생성
- Lambda 프록시 통합 구성
- API 배포 및 테스트
- 리소스 정리
Bash (AWS CLI with Bash script)
Note GitHub에 더 많은 내용이 있어요. 전체 예제와 설정·실행 방법은 Sample developer tutorials 저장소에서 확인할 수 있어요.
이 스크립트는 Lambda 함수 코드와 IAM 역할을 만들고, REST API를 생성해 helloworld 리소스에 Lambda 프록시 통합(AWS_PROXY)을 연결하고, 배포 후 테스트해요.
#!/bin/bash
set -euo pipefail
# Simple API Gateway Lambda Integration Script
# This script creates a REST API with Lambda proxy integration
# Generate random identifiers
FUNCTION_NAME="GetStartedLambdaProxyIntegration-$(openssl rand -hex 4)"
ROLE_NAME="GetStartedLambdaBasicExecutionRole-$(openssl rand -hex 4)"
API_NAME="LambdaProxyAPI-$(openssl rand -hex 4)"
# Get AWS account info
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=$(aws configure get region || echo "us-east-1")
# Validate inputs
if [[ -z "$ACCOUNT_ID" ]] || [[ -z "$REGION" ]]; then
echo "Error: Failed to retrieve AWS account information" >&2
exit 1
fi
echo "Creating Lambda function code..."
# Create Lambda function code with input validation
cat > lambda_function.py << 'EOF'
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
try:
logger.info("Received event: %s", json.dumps(event))
greeter = 'World'
# Safely retrieve greeter from query string parameters
query_params = event.get('queryStringParameters') or {}
if isinstance(query_params, dict) and 'greeter' in query_params:
greeter_value = query_params.get('greeter')
if isinstance(greeter_value, str) and greeter_value:
greeter = greeter_value
# Safely retrieve greeter from multi-value headers
multi_headers = event.get('multiValueHeaders') or {}
if isinstance(multi_headers, dict) and 'greeter' in multi_headers:
greeter_list = multi_headers.get('greeter', [])
if isinstance(greeter_list, list) and greeter_list:
greeter = " and ".join(str(g) for g in greeter_list if g)
# Safely retrieve greeter from headers
headers = event.get('headers') or {}
if isinstance(headers, dict) and 'greeter' in headers:
greeter_value = headers.get('greeter')
if isinstance(greeter_value, str) and greeter_value:
greeter = greeter_value
# Safely retrieve greeter from body
body = event.get('body')
if body and isinstance(body, str):
try:
body_dict = json.loads(body)
if isinstance(body_dict, dict) and 'greeter' in body_dict:
greeter_value = body_dict.get('greeter')
if isinstance(greeter_value, str) and greeter_value:
greeter = greeter_value
except (json.JSONDecodeError, ValueError) as e:
logger.warning("Failed to parse body: %s", str(e))
# Sanitize greeter to prevent injection
greeter = greeter.replace('"', '\\"').replace("'", "\\'")
response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": json.dumps({"message": f"Hello, {greeter}!"})
}
logger.info("Response: %s", json.dumps(response))
return response
except Exception as e:
logger.error("Unexpected error: %s", str(e), exc_info=True)
return {
"statusCode": 500,
"headers": {
"Content-Type": "application/json"
},
"body": json.dumps({"error": "Internal server error"})
}
EOF
# Create deployment package
zip -q function.zip lambda_function.py || {
echo "Error: Failed to create function.zip" >&2
exit 1
}
echo "Creating IAM role..."
# Create IAM trust policy
cat > trust-policy.json << 'EOF'
{
"Version":"2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
# Create IAM role with error handling
aws iam create-role \
--role-name "$ROLE_NAME" \
--assume-role-policy-document file://trust-policy.json \
--description "Temporary role for Lambda execution" || {
echo "Error: Failed to create IAM role" >&2
exit 1
}
aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=apigateway-lambda-integration
# Attach execution policy
aws iam attach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" || {
echo "Error: Failed to attach IAM policy" >&2
exit 1
}
# Wait for role propagation
sleep 15
echo "Creating Lambda function..."
# Create Lambda function with Python 3.11 (more recent runtime)
aws lambda create-function \
--function-name "$FUNCTION_NAME" \
--runtime python3.11 \
--role "arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME" \
--handler lambda_function.lambda_handler \
--zip-file fileb://function.zip \
--timeout 30 \
--memory-size 128 \
--environment "Variables={LOG_LEVEL=INFO}" \
--tags project=doc-smith,tutorial=apigateway-lambda-integration || {
echo "Error: Failed to create Lambda function" >&2
exit 1
}
echo "Creating API Gateway..."
# Create REST API with minimum logging
API_RESPONSE=$(aws apigateway create-rest-api \
--name "$API_NAME" \
--endpoint-configuration types=REGIONAL \
--description "API for Lambda proxy integration tutorial" \
--tags project=doc-smith,tutorial=apigateway-lambda-integration \
--output json)
API_ID=$(echo "$API_RESPONSE" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)
if [[ -z "$API_ID" ]]; then
echo "Error: Failed to create API Gateway" >&2
exit 1
fi
# Get root resource ID
ROOT_RESOURCE_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query 'items[?path==`/`].id' --output text)
# Create helloworld resource
aws apigateway create-resource \
--rest-api-id "$API_ID" \
--parent-id "$ROOT_RESOURCE_ID" \
--path-part helloworld || {
echo "Error: Failed to create resource" >&2
exit 1
}
# Get resource ID
RESOURCE_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query "items[?pathPart=='helloworld'].id" --output text)
# Create ANY method with no authorization (intentional for tutorial)
aws apigateway put-method \
--rest-api-id "$API_ID" \
--resource-id "$RESOURCE_ID" \
--http-method ANY \
--authorization-type NONE || {
echo "Error: Failed to create method" >&2
exit 1
}
# Set up Lambda proxy integration
LAMBDA_URI="arn:aws:apigateway:$REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:$REGION:$ACCOUNT_ID:function:$FUNCTION_NAME/invocations"
aws apigateway put-integration \
--rest-api-id "$API_ID" \
--resource-id "$RESOURCE_ID" \
--http-method ANY \
--type AWS_PROXY \
--integration-http-method POST \
--uri "$LAMBDA_URI" || {
echo "Error: Failed to create integration" >&2
exit 1
}
# Grant API Gateway permission to invoke Lambda
STATEMENT_ID="apigateway-invoke-$(openssl rand -hex 4)"
SOURCE_ARN="arn:aws:execute-api:$REGION:$ACCOUNT_ID:$API_ID/*/*"
aws lambda add-permission \
--function-name "$FUNCTION_NAME" \
--statement-id "$STATEMENT_ID" \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "$SOURCE_ARN" || {
echo "Error: Failed to add Lambda permission" >&2
exit 1
}
# Deploy API
aws apigateway create-deployment \
--rest-api-id "$API_ID" \
--stage-name test \
--description "Test deployment" || {
echo "Error: Failed to deploy API" >&2
exit 1
}
echo "Testing API..."
# Test the API
INVOKE_URL="https://$API_ID.execute-api.$REGION.amazonaws.com/test/helloworld"
echo "API URL: $INVOKE_URL"
# Test with query parameter (with proper URL encoding)
echo "Testing with query parameter:"
curl -s -X GET "$INVOKE_URL?greeter=John" | jq . 2>/dev/null || curl -s -X GET "$INVOKE_URL?greeter=John"
echo ""
# Test with header
echo "Testing with header:"
curl -s -X GET "$INVOKE_URL" \
-H 'content-type: application/json' \
-H 'greeter: John' | jq . 2>/dev/null || curl -s -X GET "$INVOKE_URL" \
-H 'content-type: application/json' \
-H 'greeter: John'
echo ""
# Test with body
echo "Testing with POST body:"
curl -s -X POST "$INVOKE_URL" \
-H 'content-type: application/json' \
-d '{"greeter": "John"}' | jq . 2>/dev/null || curl -s -X POST "$INVOKE_URL" \
-H 'content-type: application/json' \
-d '{"greeter": "John"}'
echo ""
echo "Tutorial completed! API is available at: $INVOKE_URL"
# Cleanup
echo "Cleaning up resources..."
# Delete API
aws apigateway delete-rest-api --rest-api-id "$API_ID" || echo "Warning: Failed to delete API" >&2
# Delete Lambda function
aws lambda delete-function --function-name "$FUNCTION_NAME" || echo "Warning: Failed to delete Lambda function" >&2
# Detach policy and delete role
aws iam detach-role-policy \
--role-name "$ROLE_NAME" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" || echo "Warning: Failed to detach policy" >&2
aws iam delete-role --role-name "$ROLE_NAME" || echo "Warning: Failed to delete role" >&2
# Clean up local files securely
rm -f lambda_function.py function.zip trust-policy.json
echo "Cleanup completed!"
API 상세는 AWS CLI Command Reference의 다음 항목을 참고해요.
AddPermission,AttachRolePolicy,CreateDeployment,CreateFunction,CreateResource,CreateRestApi,CreateRole,DeleteFunction,DeleteRestApi,DeleteRole,DetachRolePolicy,GetCallerIdentity,GetResources,GetRestApis,PutIntegration,PutMethod