Articles about OpenStack and related technologies from the RDO community

As Software Developers , we sometimes need to create a simple server that can accept some REST queries without wasting too much time. It’s always appealing to build our own components as it ensures our needs will be met. While REST sounds basic and easy to implement, to get a full REST server working is not trivial, especially when you want shiny features like HATEOAS ( https://en.wikipedia.org/wiki/HATEOAS ), pagination support, query filter, multiple content type (JSON, XML, plain text, …) support, If-Match/ETag, etc.

Let me walk you through a simple way of doing this using Python-Eve and Eve-SQLAlchemy.

Python-Eve

Eve is an open source Python REST API framework designed for human beings. It allows to effortlessly build and deploy highly customizable, fully featured RESTful Web Services.

Eve is built on top of Flask and gives the ability to easily extend an existing application to add REST routes. Those routes are directly associated to “resources” objects. Eve is historically associated with MongoDB. The resources objects were MongoDB collections but it is now possible to use SQLAlchemy or ElasticSearch instead.

The goal of this example if to show how to prepare a REST microservice based on Python-Eve and a SQL database. To do so, we will create a lightweight application to trace hateful and trollish comments from social media sites. The idea is to provide a central database be able to spot the same comment on different web site or help the moderator to block users. We will first prepare a REST back-end that we will consume later from a JavaScript Interface.

Requirements

We will use PostgreSQL for this example but you can use any engine supported by SQLAlchemy. Let’s install it:

sudo dnf install postgresql-server

Our DB structure

We will now start your application. For the moment it will be a sole wsgi.py file and we will use python3. We will see later in another article how we can split the application in different files.

We can now create our real class and register it in Eve thanks to the @registerSchema decorator:

1

2

3

4

5

6

7

8

@registerSchema('submission')

classSubmission(CommonColumns):

__tablename__='submission'

url=Column(String(2000))

author=Column(String(200))

author_url=Column(String(2000))

author_icon=Column(String(2000))

comment=Column(String(5000))

Eve configuration

The DB description is complete. We now need to configure Eve. Eve is configured through a Python dictionary that is shared for the whole application. You can also overload the configuration with a resource specific dictionary.

For the moment, we want to accept new record creation for anyone. We will see how to
turn authentication and permission later.

1

2

3

4

5

6

7

8

9

SETTINGS={

'SQLALCHEMY_DATABASE_URI':('postgresql:///'

'?host=/tmp/pg_db&dbname=template1'),

'RESOURCE_METHODS':['GET','POST'],

'ITEM_METHODS':['GET'],

'DOMAIN':{

'submission':Submission._eve_schema['submission'],

},

}

SQLALCHEMY_DATABASE_URL is the address of our PostgreSQL instance. to keep thing simple, we use a local socket.

RESOURCE_METHODS and ITEM_METHODS: since permission won’t be enabled yet, we should only accept new items creation which we cover with the POST request. We also accept GET for the moment in order to expose the content of the server DB, this way it will be easier to understand what’s going on. These configuration keys, like the others are covered by the Eve documentation.

Application creation

We will now initialize our Eve object and configure it to use the SQLAlchemy engine.

1

2

3

4

5

6

7

8

9

application=Eve(auth=None,settings=SETTINGS,data=SQL)

# bind SQLAlchemy

db=application.data.driver

Base.metadata.bind=db.engine

db.Model=Base

db.create_all()

if__name__=="__main__":

application.run(debug=True)

Data structure validation

As we said previously, Python-Eve was historically backed by MongoDB. MongoDB is a no-SQL database with no constraint. That’s why Eve allow the use of an extra configuration to validate the format of the resource. This is the purpose of the
validator as an extra argument.
This
validator is an object that will validate the dataset integrity from the application level using Cerberus. This topic is also covered by the validation page in the documentation.

You can pass the ValidorSQL object when you initialize the application object.

It’s still a good idea to use database level constraint to ensure the integrity of the data and as a bonus point, Eve-SQLAlchemy is able to understand some of them and use them to initialize ValidatorSQL default value.

boilerplate

Our application is mostly ready, we need to do the proper
import calls.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

fromsqlalchemy importColumn

fromsqlalchemy importDateTime

fromsqlalchemy importfunc

fromsqlalchemy importInteger

fromsqlalchemy importString

fromsqlalchemy.ext.declarative importdeclarative_base

# Eve imports

fromeve importEve

fromeve_sqlalchemy importSQL

fromeve_sqlalchemy.validation importValidatorSQL

# Eve-SQLAlchemy imports

fromeve_sqlalchemy.decorators importregisterSchema

Rock’n roll

For now, we use a user instance of PostgreSQL to run our application. This can easily be done with PostgreSQL with the following calls:

1

2

3

4

5

6

7

8

# Purge any existing DB directory

$rm-rf/tmp/pg_db/

# initialize the local PostgreSQL database store

$initdb--no-locale--nosync/tmp/pg_db

# Disable the network support, we will only use the local socket

$echo"listen_addresses = ''">>/tmp/pg_db/postgresql.conf

# Finally start the postgre process in the foreground

$postgres-F-k/tmp/pg_db-D/tmp/pg_db

We can now run our server:

1

$python wsgi.py

Our server is now up and running, we can access it on http://127.0.0.1:5000 and browse the nice home interface generated by Python-Eve.

We can view this first post in the submission item list at http://127.0.0.1:5000/submission or directly at http://127.0.0.1:5000/submission/1. Here again, Python-Eve do all the work for us.

OpenShift

At this point, our RESTful service is ready to go live and accept public submission. Let’s use a PaaS service to publish it on Internet. Let’s pick one at random and use Openshift.

Let’s adjust the code

First, our little application depend on Eve-SQLAlchemy and Eve. requirements.txt is used by the Python component to declare the external dependencies, let’s just specify that we use it, this way the user will just have to run
pip install-rrequirements.txt to deploy the application dependencies:

1

echoEve-SQLAlchemy>requirements.txt

To be able to use OpenShift, we just need to point the URI to the PostgreSQL instance. OpenShift exports some environment variables to describe the location of the different services. We just have to reuse them.

1

2

3

4

5

6

pg_url='postgresql:///?host=/tmp/pg_db&dbname=template1'

if'OPENSHIFT_POSTGRESQL_DB_HOST'inos.environ:

pg_url='postgresql://%s:%s/%s'%(

os.environ['OPENSHIFT_POSTGRESQL_DB_HOST'],

os.environ['OPENSHIFT_POSTGRESQL_DB_PORT'],

os.environ['OPENSHIFT_APP_NAME'])

We now need to use pg_url as the URI to the PostgreSQL database.

Enable the application in OpenShift

First, you’ll need to create an account on the OpenShift website, install the rhc command and run rhc setup.

In this example mydomain is your domain as returned by the rhc domain list command.

Here bobby is the name of our application and mydomain, our domain name. Your website should be able on the http://bobby-mydomain.rhcloud.com URL. If it’s not the case, you can call
rhc tailbobby to watch the application logs.

Here it is, you can now access your API directly through: http://bobby-mydomain.rhcloud.com