API Gateway can serve S3 files directly, bypassing your application code entirely.
Let’s see it in action. Imagine you have an S3 bucket named my-static-assets-bucket containing a file images/logo.png. You want to serve this file via an API Gateway endpoint, say https://api.example.com/assets/logo.png.
Here’s how you’d set that up in API Gateway:
-
Create a REST API: In the API Gateway console, create a new REST API. You can name it something like "S3 Asset API".
-
Create a Resource: Under your API, create a resource. For our example, let’s call it
assets. Then, create a child resource underassetsnamed{proxy+}. This{proxy+}will act as a catch-all for any path segment after/assets/. -
Create a
GETMethod: On the{proxy+}resource, create aGETmethod. -
Configure Integration:
- Integration Type: Select "AWS Service".
- AWS Region: Choose the region where your S3 bucket resides.
- AWS Service: Select "Simple Storage Service (S3)".
- HTTP Method: Select "GET".
- S3 Bucket: Enter your S3 bucket name:
my-static-assets-bucket. - S3 Key: This is the crucial part. Use the path to your file, but use a mapping template to dynamically construct it. Enter:
images/{proxy}. - Use Default Timeout: Keep this checked.
-
Add Path Parameter Mapping:
- Under "Method Execution" for the
GETmethod, go to "Integration Request". - Expand "HTTP Headers". Click "Add header".
- Name:
Content-Type - Mapped from:
integration.response.header.Content-Type(This ensures the correct MIME type is passed back to the client). - Expand "URI Parameters". Click "Add path".
- Name:
proxy - Mapped from:
method.request.path.proxy
- Under "Method Execution" for the
-
Deploy the API: Deploy your API to a stage (e.g.,
prod).
Now, when you access https://<your-api-id>.execute-api.<region>.amazonaws.com/prod/assets/images/logo.png, API Gateway will:
- Take the path segment
images/logo.pngfrom the request URL. - Use this segment as the S3 Key, looking for
images/logo.pnginmy-static-assets-bucket. - Retrieve the file from S3.
- Return the file content and its
Content-Typeheader directly to the client.
The most surprising true thing about this setup is that you don’t need to configure any Lambda functions or custom application logic for serving static files. API Gateway’s integration with S3 is a first-class feature designed for this exact purpose, making it incredibly efficient for distributing static assets. It handles the HTTP request, translates it into an S3 GetObject API call, and streams the response back.
The Content-Type header is automatically inferred by S3 based on the file extension. If S3 can’t determine the content type, it defaults to binary/octet-stream. You can also set custom Content-Type metadata directly on your S3 objects if needed.
The real power here is in the {proxy+} resource and the images/{proxy} S3 key mapping. The + in {proxy+} signifies a greedy path variable, meaning it will capture one or more path segments. When you request assets/images/logo.png, the proxy variable in the S3 key mapping (images/{proxy}) will be populated with images/logo.png. This allows you to serve files from any subdirectory within your S3 bucket by simply changing the path in your API Gateway endpoint.
The Content-Type header mapping is also important. Without it, the client might not receive the correct MIME type, leading to browsers trying to download images as plain text or failing to render them. By mapping integration.response.header.Content-Type, you’re telling API Gateway to pass through the Content-Type header that S3 provides for the requested object.
This pattern is incredibly useful for serving single-page application (SPA) assets (HTML, CSS, JS, images) or any other static content where you want a custom domain and potentially authentication/authorization managed by API Gateway, without the overhead of a compute layer.
The next thing you’ll likely want to explore is how to secure these S3 assets using API Gateway’s authorization mechanisms, such as IAM or Cognito.