Building the S3 API in Amazon API Gateway

If you have ever used the Amazon API Gateway to build an application backend, you are probably familiar with most of its integration capabilities, like Lambda functions, other HTTP endpoints like EC2 instances, or even just mock response. But did you know that Amazon API Gateway can also integrate with almost every other AWS service out there?

Since most AWS services expose their own APIs, an API built in API Gateway can simply wrap the service APIs with your own. This has numerous advantages:

  • The API Gateway to AWS service integrations are “direct”. There is no Lambda function or other piece of code sitting between the gateway and your intended service.
    • If you have been using Lambda simply as an intermediary to invoke another AWS service from API Gateway, you can do away with this approach and save the extra hop and latency introduced in every request-response cycle.
  • Your API in API Gateway can be truly “yours”, down to every detail: the names of your URL endpoints, what parameters they take, the shape (schema) of their request and response bodies, etc.
    • This lets you completely abstract away the underlying service API details and its AWS-ness. You can use mapping templates in the gateway to transform the input/output into any format suitable for your end-user apps.
  • You can even cherry-pick specific APIs from the AWS service you need and combine them into a single API in API Gateway. This way, from your application’s perspective, it’s simply calling various endpoints under a single API base URL, without knowing how its request is being distributed to several AWS services in the background.
  • Authentication: If your app were to invoke AWS service APIs directly, it is forced to use AWS-specific auth techniques. But if you wrap the service APIs in another API in API Gateway, you can add any kind of auth mechanism to it: Cognito, IAM, or even custom Lambda functions.

In this post, we will build a small subset of the S3 API in API Gateway using this “direct service integration” approach, in order to learn how it works.

List All Buckets API

Start by going to the API Gateway console and click Create REST API. Create a new API named MyS3API:

First, we add a GET method to the “/” resource. This will perform the “list all S3 buckets” action. Configure this method as shown below:

Note the execution role used above. This is an IAM role I created earlier. It has the trusted entity of so API Gateway can assume this role and it has the following permission policies attached: AmazonS3FullAccess and AmazonAPIGatewayPushToCloudWatchLogs. This allows API Gateway to perform all S3 actions and also write logs to CloudWatch.

Next, add the 400 and 500 HTTP response status codes to the GET method so our API doesn’t always return the default 200 response:

Next, add the Content-Type and Content-Length HTTP headers to the 200 response code:

Now map all 4XX S3 responses to our 400 response code and all 5XX to our 500:

Now create the header mappings. Expand the 200 response and map the headers returned by the S3 response to the ones we created earlier:

Important Note: We are not securing our API with an auth mechanism here because this is just for learning purposes, but if you use this approach in your projects, you’ll definitely need to secure the API using either IAM, Cognito, or Lambda.

If you try testing out the GET method now from the console, you’ll see it works as expected. All buckets are returned in the response:

Also, note that the Content-Type in the response header is correctly set to XML now instead of the default JSON because we mapped the headers accordingly:

Create Bucket API

Add a /{bucket} resource:

Add a PUT method to it to create buckets:

Notice the path override is set to {bucket}. Map this to the bucket parameter we get in the request:

Add the Content-Type header to the Method Request:

Go back to the Integration Request and map the Content-Type header as we did for the “GET /” resource:

Notice the inclusion of a couple more headers other than Content-Type. These are S3-specific headers as explained below:

  • x-amz-acl sets the ACL for the uploaded object. We set it to authenticated-read so only authenticated users with access to this bucket can see the object.
  • The Expect header is set to 100-continue and ensures that the request payload is only submitted when the request parameters are validated.

Now test the API:

The bucket was successfully created!

You can redo the steps in this section to create the GET /{bucket} and DELETE /{bucket} API endpoints.


In this article, we created a CRUD API for the S3 service using API Gateway’s native integration with the S3 service. You can follow a similar approach for integrating API Gateway with any other AWS service.

About the Author ✍🏻

Harish KM is a Principal DevOps Engineer at QloudX & a top-ranked AWS Ambassador since 2020. 👨🏻‍💻

With over a decade of industry experience as everything from a full-stack engineer to a cloud architect, Harish has built many world-class solutions for clients around the world! 👷🏻‍♂️

With over 20 certifications in cloud (AWS, Azure, GCP), containers (Kubernetes, Docker) & DevOps (Terraform, Ansible, Jenkins), Harish is an expert in a multitude of technologies. 📚

These days, his focus is on the fascinating world of DevOps & how it can transform the way we do things! 🚀

Leave a Reply

Your email address will not be published. Required fields are marked *