Sharing API Gateway with Multiple Services in Serverless Framework
While working on my little side project JSONPerf (check it out: jsonperf.com), I stumbled upon an interesting problem I thought was worth sharing with you.
A quick summary of what JSONPerf is will help us understand the need before discussing the solution.
The project's goal is to benchmark JSON libraries' performance in different programming languages. One of the features it provides is uploading a JSON file and benchmarking the different libraries on the user's specific file.
To implement this feature, I decided to implement the per-language benchmark endpoint using AWS Lambda as it provides me flexibility and I can use a different runtime for each function.
The problem I stumbled upon is the fact that in my serverless framework definitions file, I need to have multiple endpoints ( /python3
, /python2
, /java
etc.) under the same API, each using a different language (runtime).
Unfortunately, this quickly turned out to be impossible because the python requirements plugin currently doesn't support my setup.
It allows you to specify different requirements file per function, but only if the file is called requirements.txt and the code is in different folders (github issue).
In my case, both Python 2 and Python 3 functions share the same code but have different requirements (different libraries to compare).
To solve it, I created a main serverless.yml that declares an API Gateway which is then shared between the other, per-function serverless.yml files.
Main (API) serverless.yml
file
service: api
provider:
name: aws
stage: dev
region: us-east-1
resources:
Resources:
ApiGw:
Type: AWS::ApiGateway::RestApi
Properties:
Name: ApiGw
Outputs:
apiGatewayRestApiId:
Value:
Ref: ApiGw
Export:
Name: ApiGw-restApiId
apiGatewayRestApiRootResourceId:
Value:
Fn::GetAtt:
- ApiGw
- RootResourceId
Export:
Name: ApiGw-rootResourceId
Services files, Python 2 example python/serverless_py2.yml
service: python2
plugins:
- serverless-python-requirements
- serverless-wsgi
package:
exclude:
- 'venv*/**'
custom:
wsgi:
app: app.app
packRequirements: false
pythonRequirements:
fileName: requirements_py2.txt
dockerizePip: non-linux
slim: true
provider:
name: aws
stage: dev
region: us-east-1
runtime: python2.7
apiGateway:
restApiId:
'Fn::ImportValue': ApiGw-restApiId
restApiRootResourceId:
'Fn::ImportValue': ApiGw-rootResourceId
websocketApiId:
'Fn::ImportValue': ApiGw-websocketApiId
functions:
python2:
handler: wsgi_handler.handler
events:
- http:
method: post
path: /python2
cors: false
This is of course just an example and you can tweak it as much as you want with the flexibility you gain.
Hope this will help someone in finding the little hidden documentation to accomplish that using serverless framework.