Create a REST API with Lambda proxy integration
The following code example shows how to:
Create an IAM role for Lambda execution
Create and deploy a Lambda function
Create a REST API
Configure Lambda proxy integration
Deploy and test the API
Clean up resources
- Bash
-
- AWS CLI with Bash script
-
Note
There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials
repository. #!/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!"-
For API details, see the following topics in AWS CLI Command Reference.
-
For a complete list of AWS SDK developer guides and code examples, see Using Lambda with an AWS SDK. This topic also includes information about getting started and details about previous SDK versions.
Create a REST API to track COVID-19 data
Create a lending library REST API