Third party APIs are a great way to add functionality to your application. However, you are limited to what they offer and in most cases there’s no way to control the rate at which you can call them. Even AWS doesn’t offer any way to limit the number of calls you can make to their APIs.
This is where AWS API Gateway comes in. It allows you to create a proxy for third party APIs, control access with your own API keys and apply rate limits for each key. You can even transform the request and/or response before sending it to the third party API.
In my case I’ve been working on a service that uses OpenAI’s Dall-E API to generate images, users can then call the service using my OpenAI key, but the issue is that I don’t want to share my key with everyone. I also want to limit the number of calls each user can make to the API to prevent abuse and to make sure I don’t go over my monthly limit.
In the next section we’ll go over how to create an API Gateway proxy for OpenAI, but you can use the same steps for any other third party API.
TL;DR
If you just want to try it out with OpenAI you can click the following button to deploy the CloudFormation stack to your AWS account.
the code is also available on GitHub.
Create an API Gateway proxy for OpenAI using CloudFormation
We could use the AWS console directly and start creating resources, but it’s much better to use CloudFormation to manage infrastructure as code. It’s repeatable and can be versioned using git.
Here’s the CloudFormation template we’ll be using:
Parameters:
OpenAIKey:
Type: String
Description: The OpenAI API key
QuotaLimit:
Type: Number
Description: The quota limit for the usage plan
Default: 1000
ThrottleBurstLimit:
Type: Number
Description: The burst limit for the throttle settings
Default: 200
ThrottleRateLimit:
Type: Number
Description: The rate limit for the throttle settings
Default: 100
Resources:
OpenAIApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: OpenAIApiGateway
OpenAIApiResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref OpenAIApiGateway
ParentId: !GetAtt OpenAIApiGateway.RootResourceId
PathPart: '{proxy+}'
OpenAIApiMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref OpenAIApiGateway
ResourceId: !Ref OpenAIApiResource
HttpMethod: ANY
AuthorizationType: NONE
ApiKeyRequired: true
RequestParameters:
method.request.path.proxy: true
Integration:
Type: HTTP_PROXY
IntegrationHttpMethod: ANY
Uri: 'https://api.openai.com/v1/{proxy}'
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
'integration.request.path.proxy': 'method.request.path.proxy'
'integration.request.header.Content-Type': "'application/json'"
'integration.request.header.Authorization': !Sub
- "'Bearer ${OpenAIKey}'"
- OpenAIKey: !Ref OpenAIKey
IntegrationResponses:
- StatusCode: 200
OpenAIApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: OpenAIApiKey
Description: API Key for OpenAI API Gateway
Enabled: true
OpenAIApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: !Ref OpenAIApiGateway
Stage: default
Description: Usage plan for OpenAI API Gateway
Quota:
Limit: !Ref QuotaLimit
Period: MONTH
Throttle:
BurstLimit: !Ref ThrottleBurstLimit
RateLimit: !Ref ThrottleRateLimit
OpenAIApiUsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref OpenAIApiKey
KeyType: API_KEY
UsagePlanId: !Ref OpenAIApiUsagePlan
OpenAIApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: OpenAIApiMethod
Properties:
RestApiId: !Ref OpenAIApiGateway
OpenAIApiStage:
Type: AWS::ApiGateway::Stage
Properties:
StageName: default
RestApiId: !Ref OpenAIApiGateway
DeploymentId: !Ref OpenAIApiDeployment
OpenAIApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
ApiStages:
- ApiId: !Ref OpenAIApiGateway
Stage: !Ref OpenAIApiStage
Outputs:
OpenAIApiUrl:
Description: The URL for OpenAI API Gateway
Value: !Join
- ''
- - 'https://'
- !Ref OpenAIApiGateway
- '.execute-api.'
- !Ref 'AWS::Region'
- '.amazonaws.com/default'
Let’s go over each section and see what it does.
Parameters
The first section defines the parameters we’ll be using in the template. We’ll be using the OpenAI key to authenticate with the API, and we’ll also define the quota and throttle limits for the usage plan. Only the OpenAI key is required, the other parameters have default values.
Resources
This section defines the resources we’ll be creating. We’ll create an API Gateway REST API, a resource, a method, an API key, a usage plan, a usage plan key, a deployment and a stage.
Outputs
The last section defines the outputs for the stack. We’ll be using the API URL to test the proxy.
Using the proxy
Once the stack is created you can go to the API Gateway console and find the URL for the API, then go to the usage plan and find the API key or generate a new one.
Since we’re using OpenAI’s API as an example, the following javascript code will generate an image using the proxy:
import OpenAI from 'openai';
const openai = new OpenAI({
baseURL: 'API_GATEWAY_PROXY_URL', // Looks like https://xxxxxx.execute-api.us-east-1.amazonaws.com/default
defaultHeaders: {
'x-api-key': 'API_KEY_FROM_USAGE_PLAN'
}
});
async function main() {
const imageCompletion = await openai.images.generate({
model: 'dall-e-3',
prompt: 'an image of a cute cat',
})
console.log('imageCompletion', imageCompletion);
}
main();
and just in case you’re wondering what the image looks like:
Conclusion
The API Gateway service is very powerful and offers so much more than what we covered in this tutorial. For further reading I recommend checking out the official documentation.