Developing API exchange sharing service - Part II

Please check the previous part to know the background of this project.

In this part, we'll dive into code and deploy a simple API to AWS Lambda and Api Gateway.

I'll be using Python Flask framework for defining the APIs and Serverless framework to manage the infrastructure and deployment.

Please make sure you have Python3 and relatively newer version of nodejs installed and working to follow along.

The first step is to create a new project folder and initialise package.json file which will be used to define and install Serverless plugins.

$ mkdir api-exchange-server
$ cd api-exchange-server

$ npm init
$ # Enter all the way to generate package.json file

Installing Serverless CLI.

$ npm install -D serverless # Although better to install this globally

If Serverless CLI is installed globally then you don't need to prefix the serverless commands with ./nodes_modules/.bin/.

Let's create a new project

$ ./node_modules/.bin/serverless
Name the project serverless-project. Ignore the project name as we'll move the files to the current folder.

We'll just copy the files that we need from the generated project.

$ mv serverless-project/serverless.yml .
$ mv serverless-project/.gitignore .
$ rm -rf serverless-project

After removing the folder generated by the Serverless CLI, this is how the structure looks like

$ ls -la
total 336
drwxr-xr-x    7 nmn  staff     224  1 Jan 09:00 .
drwxr-xr-x   15 nmn  staff     480  1 Jan 08:53 ..
-rw-r--r--    1 nmn  staff     192  1 Jan 08:58 .gitignore
drwxr-xr-x  386 nmn  staff   12352  1 Jan 08:54 node_modules
-rw-r--r--    1 nmn  staff  156725  1 Jan 08:54 package-lock.json
-rw-r--r--    1 nmn  staff     271  1 Jan 08:54 package.json
-rw-r--r--    1 nmn  staff    3206  1 Jan 08:58 serverless.yml

Let's open the folder in your favourite text editor.

To connect AWS Lambda to Flask handlers, we'll need to install serverless-wsgi plugin to do the necessary transformation.

$ ./node_modules/.bin/serverless plugin search -q wsgi
1 plugin(s) found for your search query "wsgi"

serverless-wsgi - Serverless plugin to deploy WSGI applications (Flask/Django/Pyramid etc.) and bundle Python package

To install a plugin run 'serverless plugin install --name plugin-name-here'

It will be automatically downloaded and added to your package.json and serverless.yml file

As stated by the really useful help message, we'll install this plugin.

$ ./node_modules/.bin/serverless plugin install --name serverless-wsgi

Next, we'll create a simple flask Api which will return the environment variables in json. As this code will run on Lambda, you'll be able to see all the environment variables available for the function.

File -> New -> “api.py”

import os
from flask import Flask, jsonify

app = Flask(__name__)


@app.route("/", methods=["GET"])
def environ():
    return jsonify({k:v for k, v in os.environ.items()})

Just noticed that we haven't installed Flask yet so let's create a requirements file and install it in a new virtualenv.

$ python3 -m venv venv
$ source venv/bin/activate
$ pip install flask
$ pip freeze > requirements.txt

With the project completed, we can test the Api by running it locally.

$ FLASK_APP=api.py flask run

Next we need to tell/configure Serverless framework to connect Lambda to Flask App. There are few ways to setup the integration. Here we'll be using AWS Lambda Proxy integration for the API handler.

functions:
  api:
    handler: wsgi_handler.handler
    events:
      - http: ANY /
      - http: ANY {proxy+}

We also need to tell wsgi plugin where to find the Flask API, so let define a custom section for this.

custom:
  wsgi:
    app: api.app

Although the wsgi plugin can manage python dependencies, I had better luck with using a different plugin serverless-python-requirements so we'll install it as well

$ ./node_modules/.bin/serverless plugin install --name serverless-python-requirements

Now let's try packaging up the app.

$ ./node_modules/.bin/serverless package

If successful, the generated zip file will be placed in .serverless folder. If we examine that file, we'll find that it contains all the files in the current folder including the giant venv and node_modules folder 😱.

serverless package

I'm sure python requirements folder is right up there as well.

Luckily, we can configure what to include in the zip file so we'll exclude everything and just add the file that we need to run the application. Note that the plugin will still take care of all the python dependencies defined in requirements.txt file.

package:
  exclude:
    - "**"
  include:
    - "api.py"

This is what it looks like with the changes that we made in the serverless.yml file.

Serverless wsgi setup

You can also check the complete file.

That should be everything to deploy on AWS Lambda. The next step requires an AWS profile with appropriate permissions to deploy and create Lambda resources.

Note that this is where you may be charged.

$ AWS_PROFILE=myprofile ./node_modules/.bin/serverless deploy -v

It will take some time to create all the resources before printing out the endpoints that it generated for the Api Gateway.

Serverless output

You should be able to hit the above endpoint via curl or open it up directly in the browser. There you can see all the environment variables available to your lambda function.

curl -v https://mcb1lbc2ti.execute-api.us-east-1.amazonaws.com/dev
# or 
open https://mcb1lbc2ti.execute-api.us-east-1.amazonaws.com/dev

Once you are done with it, don't forget to remove the setup.

$ AWS_PROFILE=myprofile ./node_modules/.bin/serverless remove -v