How to build a simple RESTful API with Flask

I built this proof of concept (POC) for another project someone else was working on. They had built a basic RESTful API using Flask. But needed to add authentication and HTTPS support.

I was pleasantly surprised how easy it was to go from zero to a basic RESTful API with TLS HTTPS and authentication via URL argument or headers.

I'm writing this post to demonstrate how easy it truly is to setup a simple, safe and secure RESTful API using Flask.

Step 1  Install Python
I'll skip the steps on how to install Python. But I will just say that I got this working easily with both Python 2.7 on Linux and Python 3.5 on Windows.

Step 2  Install Flask and clone my repo
Flask is also easy to install by following their Quickstart Installation Guide. However, stop before doing the "mkdir myproject" step and clone my "flask-api-key" repo instead.

Step 3  Activate a venv
Then do:
$ cd flask-api-key
$ virtualenv venv
New python executable in venv/bin/python
Installing setuptools, pip............done.
Now, whenever you want to work on this project, you only have to activate the corresponding environment. On OS X and Linux, do the following:
$ . venv/bin/activate
If you are a Windows user, the following command is for you:
$ venv\scripts\activate

Step 4  Start Flask
Now you just need to start Flask. In Linux do this:
$ export FLASK_APP=goaway.py
$ flask run
 * Running on http://127.0.0.1:443/
In Windows do this:
$ set FLASK_APP=goaway.py
$ flask run
 * Running on http://127.0.0.1:443/
Now Flask is listening on port 443 on localhost (127.0.0.1)

Step 5 Test
Open another terminal and perform 3 tests:

GET
$ curl -k https://127.0.0.1
Hellow world!
Flask server output:
127.0.0.1 - - [23/Oct/2016 14:55:55] "GET / HTTP/1.1" 200 -


POST - 200 Authentication Success

Key in header

$ curl -k -H "Content-Type: application/json" -H "x-api-key: eiWee8ep9due4deeshoa8Peichai8Ei2" -X POST -d '{"foo":"xyz","bar":"xyz"}' https://127.0.0.1/json/
Posted JSON!
Flask server output:
127.0.0.1 - - [23/Oct/2016 14:55:26] "POST /json/ HTTP/1.1" 200 -
POST - 401 Authentication Failure

Key in header

$ curl -k -H "Content-Type: application/json" -H "x-api-key: <wrong_key>" -X POST -d '{"foo":"xyz","bar":"xyz"}' https://127.0.0.1/json/
Flask server output:
127.0.0.1 - - [23/Oct/2016 14:55:26] "POST /json/ HTTP/1.1" 401-
API Key in arguments
If you want to have the API key provided via URL arguments, you'll need to uncomment this line:

#if request.args.get('key') and request.args.get('key') == key:

And comment this line:

if request.headers.get('x-api-key') and request.headers.get('x-api-key') == key:

Then on the client side test has to look like this:

curl -k -H "Content-Type: application/json" -X POST -d '{"foo":"xyz","bar":"xyz"}' https://127.0.0.1/json/?key=eiWee8ep9due4deeshoa8Peichai8Ei2
But if you use arguments instead of headers, keep in  mind that the API key values will be output and logged by Flask like this:



127.0.0.1 - - [23/Oct/2016 14:55:26] "POST /json/?key=eiWee8ep9due4deeshoa8Peichai8Eih HTTP/1.1" 200 -
Conclusion
It only took me a few hours of research, coding and testing to get Flask to require an API key via URL arguments or headers using HTTPS over TLS with the API key stored in a file and not code. I consider these features the bare minimum for a truly useful RESTful API.

Keep in mind that this is still a very basic and simple RESTful API. It's missing many things like the ability to accept and process hundreds of thousands of concurrent API calls, including traffic management, authorization and access control, monitoring, and API version management. If you need a full featured and robust API, consider something like AWS's or Azures API Gateway service.

Comments

Popular posts from this blog

Authentication for RESTful APIs

How to build a simple RESTful API with Flask

Security From Happiness