Does Zappa make it super easy?

In this article, I'm going to show that deployment of the "Hello World" flask application with Zappa framework is really easy. Follow the steps and see for yourself.

Getting started

At the beginning, let’s assume that we have pure Python 3 installation. Firstly, let’s install virtualenv (zappa needs it), zappa and AWS Command Line Interface:

pip install virtualenv
pip install zappa 
pip install awscli

Now, create dictionary and virtualenv for our project:

mkdir brave-zappa-tutorial
virtualenv brave-zappa

And activate the venv:

source brave-zappa/bin/activate

Flask App

It’s time to create our flask hello.py (minimal working example from flask tutorial):

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
  return 'Hello, World!'

Let’s test the app and type in console:

export FLASK_APP=hello.py
flask run

When you visit website localhost:5000 in your browser, you will see “Hello World” from our application.

AWS Deployment

Now, we need to take step to deploy app on AWS Lambda. Firstly, set up your AWS credentials, run

aws configure

and follow the terminal wizard. As a result of execution this script, files under ~/.aws will be created. The next thing to do is creation of “zappa_settings.json” file. Command:

zappa init

will create initial setup. If it is necessary, you can add additional entries to this file i.e:

  • aws_region
  • roles entries (if role problem occurs, you’ ll have to set “manage_roles” to false and set “role_name”, “role_arn” by yourself.

And that’s it! Project is ready to deploy. Just you need to run (you need proper rights to manage stack):

zappa deploy 

And project will be packet and send to the default stage. Zappa provides many additional functions, i.e:

  • update -  updates project on the server
  • Rollback  - rollbacks to a previous version
  • Undeploy - removes the API Gateway and Lambda function
  • Status -  checks status of your deployment
  • Tail - shows logs

And many more! Everything you’ll find on the zappa’s github page.

Bonus! Working with DynamoDB

The application described below is very simple, let’s make them more advanced and add support for DynamoDB. Let’s assume  that we want to create table to store users of our service.

Setup local DynamoDB

If you want to test the database locally, you have to download them from: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html - A more detailed description is available in the this link. Unpack and run(jre 6.x or newer is required):

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

User table creation

Now, let’s create basic table to keep the user data. We need to add:

app.config['DYNAMO_TABLES'] = [
  dict(
      TableName='users',
      KeySchema=[dict(AttributeName='username', KeyType='HASH')],
      AttributeDefinitions=[dict(AttributeName='username', AttributeType='S')],
      ProvisionedThroughput=dict(ReadCapacityUnits=5,
                                 WriteCapacityUnits=5)
  )]

To our flask app. Let’s stop in this step for the moment and discuss the above code:

TableName it simply place for name of the table
KeySchema

specifies the attributes that make up the primary key for a table index. Of course, here you  can place more than one key, but one (and only one) must be HASH.

KeyType   the role that the key attribute will assume (HASH for partition key, RANGE for sort key).
AttributeDefinitions

attributes that describe the key schama for the table and index. AttributeType can be S (String), N (number) or B (binary).

ProvisionedThroughput  represents the throughput setting for a table
ReadCapacityUnits

The maximum number of strongly consistent reads consumed per second before DynamoDB returns a ThrottlingException.

WriteCapacityUnits

The maximum number of writes consumed per second before DynamoDB returns a ThrottlingException

Full description available here: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateTable.html If you want to use local database, let’s set:

app.config['DYNAMO_ENABLE_LOCAL'] = True
app.config['DYNAMO_LOCAL_HOST'] = 'localhost'
app.config['DYNAMO_LOCAL_PORT'] = 8000

To use the table shema, you have to add:

dynamo = Dynamo()
dynamo.init_app(app)

To create table:

with app.app_context():
   dynamo.create_all()

Additional views

We will create two simple views, that will take arguments from link and make some operations on the database:

create_user

@app.route('/put_user')
def create_user():
  username = request.args.get('username')
  first_name = request.args.get('first_name')
  dynamo.tables['users'].put_item(Item={
      'username': username,
      'first_name': first_name,
  })
  return "User created"

put _item - creates new item or update old if exist.

Get_user

@app.route('/get_user')
def get_user():
  username = request.args.get('username')
  response = dynamo.tables['users'].get_item(
      Key={
          'username': username,
      }
  )
  try:
      item = response['Item']
  except KeyError:
      return "Item not found"
  return str(item)

get_Item - returns a set of attributes for the item with the given primary key. If there is no matching item, GetItem does not return any data and there will be no Item element in the response.

Test and deploy

To test your app, run and visit http://localhost:5000/put_user?username=john_doe&first_name=john to create record: {username: john_doe, first_name:john} and http://localhost:5000/get_user?username=john_doe to get record from database

To update project on the AWS run:

zappa update

And voila! It works on the server!

Sources are avaliable on GitHub.

Task for you

Taking data from the request link isn’t user friendly, so if you want to practice your flask and programing skills you can add some forms to project.

Comments

There are currently no comments

New Comment