1 Introduction
In outline, here is our software stack:
- Python
- flask
- flask-restful
- uwsgi
- nginx
I found some very useful help here: https://iotbytes.wordpress.com/python-flask-web-application-on-raspberry-pi-with-nginx-and-uwsgi/
2 Installation
2.3 flask and flask-restful
I suggest that you use a virtualenv. Do the following:
$ pip install virtualenv $ cd where/you/want/your/virtualenvs $ virtualenv -p /usr/bin/pyton3 restplatform3 # identify as Python 3 $ source restplatform3/bin/activate # activate this virtual environment $ pip install flask flask_restful
Notes:
After activating the virtual environment, you will be running the version of Python in that virtual environment whenever you run a script or you execute $ python. And, whenever you install a Python package, e.g. with pip, it will be installed inside the virtual environment directory that you have just created. You can check this (on Linux) by running:
$ which python
The above commands create a virtual environment containing Python 3. If you prefer Python 2, omit the "-p" option and its argument.
You should also consider using pip to install a few useful things like ipython, lxml, etc.
3 Configuration and set-up
We're not the first to do this, and so there is help out on the Internet. Here are sites that I found helpful:
- https://www.digitalocean.com/community/tutorials/how-to-deploy-python-wsgi-applications-using-uwsgi-web-server-with-nginx
- http://raspberrywebserver.com/cgiscripting/setting-up-nginx-and-uwsgi-for-cgi-scripting.html
- https://iotbytes.wordpress.com/python-flask-web-application-on-raspberry-pi-with-nginx-and-uwsgi/
- http://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/
- https://sonnguyen.ws/run-a-flask-application-in-nginx-uwsgi/
- http://www.pratermade.com/2014/08/setting-up-your-raspberry-pi-environment/
4 Application development
Of course, you can write many different styles of applications that accept requests and deliver responses via HTTP. However, this current post focuses on developing an application that follows the REST application style. I've already written posts on how to do that. So, here I'm giving only a few brief notes on how to implement a simple REST application with Python and flask, specifically using the flask-restful package.
Our simple REST example application will respond to the following HTTP methods/requests:
- GET -- Either (1) return a specific document when given an ID or (2) return a list of documents.
- POST -- Create/add a new document (resource) to the collection.
- PUT -- Update a document/resource that already in the collection given the ID of an existing document and its new content.
Here is the code: flaskrest_test05.py
Notes:
- The flask-restful extension for flask enables us to (1) encode routing information and (2) write a class that implements methods that handle the various HTTP methods (GET, POST, PUT, DELETE, etc) that we want to handle.
5 Testing
You can use any of the following to drive tests for your HTTP REST application:
- curl -- See:
- httpie -- Note that although the project name is httpie, the command line tool is http. See:
- Python and the requests module -- For information on requests, see: http://docs.python-requests.org/
5.1 curl
Examples:
get-one-document.sh:
#!/bin/bash # get-one-document.sh # Retrieve a single document from the database. curl -v http://localhost:8001/documents/getdocument/$1
list-documents.sh:
#!/bin/bash # list-documents.sh # Retrieve a list of all existing documents. http://localhost:8001/documents/getdocument
add-document.sh:
#!/bin/bash # add-document.sh # Create a new document; add it to the database. curl -v -X POST http://localhost:8001/documents/adddocument -d "document=$1"
update-document.sh:
#!/bin/bash # update-document.sh # Update an existing document. curl -v -X PUT http://localhost:8001/documents/updatedocument/$1 -d "document=$2"
delete-document.sh:
#!/bin/bash -x # delete-document.sh # Delete an existing document; remove it from the database. http://localhost:8001/documents/delete/$1
5.2 httpie
httpie is a pleasant command line HTTP client and can be used as an alternative to curl. The actual command line name is "http". If you are a Python user, you can install it with pip:
$ pip install httpie
Or, on Linux, you can install it with apt-get or aptitude.
Here are several examples using httpie:
# Get a list of all documents $ http GET http://localhost:8001/documents/getdocument # Get one document by its ID $ http GET http://localhost:8001/documents/getdocument/91a3b86fcbc59cc5f4a855d7894cb3be46546dccc18f5e833d24824ff4e4bf95
5.3 Python and requests
A test driver -- You can write a simple application using the requests module (which can be installed using pip). Here is some sample code to get you started.
rook_request.py:
#!/usr/bin/env python from __future__ import print_function import requests def rook_request(): # # Request HTML. response = requests.get('http://rook.local:5000') content = response.content.decode('utf-8') print('html content: {}'.format(content)) print('-' * 60) # # Request JSON. headers = {'content-type': 'application/json'} response = requests.get('http://rook.local:5000', headers=headers) content = response.content.decode('utf-8') print('json content: {}'.format(content)) def main(): rook_request() if __name__ == '__main__': #import ipdb; ipdb.set_trace() main()
Timing -- You can get some estimates of response time using IPyton and the %timeit magic command. For example, the following uses the above Python code (in rook_request.py) and executes 10 loops with 1 call to rook_request.rook_request in each loop:
$ ipython Python 3.6.0 (default, Dec 26 2016, 10:27:00) Type "copyright", "credits" or "license" for more information. IPython 5.1.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: In [1]: import rook_request In [2]: %timeit -n 10 -r 1 rook_request.rook_request() o o o html content: <html> <head> <title>Flask test app on rook</title> </head> <body> <h1>rook test 1</h1> <p>Current time: Fri Mar 24 16:23:43 2017</p> </body> </html> ------------------------------------------------------------ json content: {"time": "Fri Mar 24 16:23:43 2017"} 10 loops, best of 1: 117 ms per loop In [3]: