A Basic RESTFul API Service with Python Flask. We will be using the Flask, jsonify and request classes to build our API service.
Description of this demonstration:
Our API will be able to do the following:
Create, Read, Update, Delete
In this demonstration, we will add some information about people to our API, then go through each method that is mentioned above.
Getting the Dependencies:
Setup the virtualenv and install the dependencies:
1
2
3
$ virtualenv .venv
$ source .venv/bin/activate
$ pip install flask
The API Server Code:
Here’s the complete code, as you can see I have a couple of decorators for each url endpoint, and a id_generator
function, that will generate id’s for each document. The id will be used for getting users information, updates and deletes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from flask import Flask , jsonify , request
from multiprocessing import Value
counter = Value ( 'i' , 0 )
app = Flask ( __name__ )
a = []
help_message = """
API Usage:
- GET /api/list
- POST /api/add data={"key": "value"}
- GET /api/get/<id>
- PUT /api/update/<id> data={"key": "value_to_replace"}
- DELETE /api/delete/<id>
"""
def id_generator ():
with counter . get_lock ():
counter . value += 1
return counter . value
@app.route ( '/api' , methods = [ 'GET' ])
def help ():
return help_message
@app.route ( '/api/list' , methods = [ 'GET' ])
def list ():
return jsonify ( a )
@app.route ( '/api/add' , methods = [ 'POST' ])
def index ():
payload = request . json
payload [ 'id' ] = id_generator ()
a . append ( payload )
return "Created: {} \n " . format ( payload )
@app.route ( '/api/get' , methods = [ 'GET' ])
def get_none ():
return 'ID Required: /api/get/<id> \n '
@app.route ( '/api/get/<int:_id>' , methods = [ 'GET' ])
def get ( _id ):
for user in a :
if _id == user [ 'id' ]:
selected_user = user
return jsonify ( selected_user )
@app.route ( '/api/update' , methods = [ 'PUT' ])
def update_none ():
return 'ID and Desired K/V in Payload required: /api/update/<id> -d \' {"name": "john"} \' \n '
@app.route ( '/api/update/<int:_id>' , methods = [ 'PUT' ])
def update ( _id ):
update_req = request . json
key_to_update = update_req . keys ()[ 0 ]
update_val = ( item for item in a if item [ 'id' ] == _id ) . next ()[ key_to_update ] = update_req . values ()[ 0 ]
update_resp = ( item for item in a if item [ 'id' ] == _id ) . next ()
return "Updated: {} \n " . format ( update_resp )
@app.route ( '/api/delete/<int:_id>' , methods = [ 'DELETE' ])
def delete ( _id ):
deleted_user = ( item for item in a if item [ 'id' ] == _id ) . next ()
a . remove ( deleted_user )
return "Deleted: {} \n " . format ( deleted_user )
if __name__ == '__main__' :
app . run ()
Demo Time:
Retrieving the Help output:
1
2
3
4
5
6
7
8
9
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api
API Usage:
- GET /api/list
- POST /api/add data ={ "key" : "value" }
- GET /api/get/<id>
- PUT /api/update/<id> data ={ "key" : "value_to_replace" }
- DELETE /api/delete/<id>
Doing a list, to list all the users, its expected for it to be empty as we have not added any info to our API:
1
2
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api/list
[]
Adding our first user:
1
2
$ curl -XPOST -H 'Content-Type: application/json' http://localhost:5000/api/add -d '{"name": "ruan", "country": "south africa", "age": 30}'
Created: { u'country' : u'south africa' , u'age' : 30, u'name' : u'ruan' , 'id' : 1}
Adding our second user:
1
2
$ curl -XPOST -H 'Content-Type: application/json' http://localhost:5000/api/add -d '{"name": "stefan", "country": "south africa", "age": 29}'
Created: { u'country' : u'south africa' , u'age' : 29, u'name' : u'stefan' , 'id' : 2}
Doing a list again, will retrieve all our users:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api/list
[
{
"age" : 30,
"country" : "south africa" ,
"id" : 1,
"name" : "ruan"
} ,
{
"age" : 29,
"country" : "south africa" ,
"id" : 2,
"name" : "stefan"
}
]
Doing a GET on the userid, to only display the users info:
1
2
3
4
5
6
7
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api/get/2
{
"age" : 29,
"country" : "south africa" ,
"id" : 2,
"name" : "stefan"
}
Now, let’s update some details. Let’s say that Stefan relocated to New Zealand. We will need to provide his id
and also the key/value that we want to update:
1
2
$ curl -XPUT -H 'Content-Type: application/json' http://localhost:5000/api/update/2 -d '{"country": "new zealand"}'
Updated: { u'country' : u'new zealand' , u'age' : 29, u'name' : u'stefan' , 'id' : 2}
As you can see the response confirmed that the value was updated, but let’s verify the output, by doing a get on his id:
1
2
3
4
5
6
7
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api/get/2
{
"age" : 29,
"country" : "new zealand" ,
"id" : 2,
"name" : "stefan"
}
And lastly, lets delete our user, which will only require the userid:
1
2
$ curl -XDELETE -H 'Content-Type: application/json' http://localhost:5000/api/delete/2
Deleted: { u'country' : u'new zealand' , u'age' : 29, u'name' : u'stefan' , 'id' : 2}
To verify this, list all the users:
1
2
3
4
5
6
7
8
9
$ curl -XGET -H 'Content-Type: application/json' http://localhost:5000/api/list
[
{
"age" : 30,
"country" : "south africa" ,
"id" : 1,
"name" : "ruan"
}
]
Using Python Requests:
We can also use python’s requests module to do the same, to give a demonstration I will create a new user:
1
2
$ pip install requests
$ python
1
2
3
4
5
6
7
8
9
10
>>> import requests
>>> import json
>>> base_url = 'http://localhost:5000/api/add'
>>> headers = { "Content-Type" : "application/json" }
>>> payload = json . dumps ({ "name" : "shaun" , "country" : "australia" , "age" : 24 })
>>> r = requests . post ( base_url , headers = headers , data = payload )
>>> r . content
Created : { u'country' : u'australia' , u'age' : 24 , u'name' : u'shaun' , 'id' : 4 }
Thats it. I’ve stumbled upon Flask-Restful which I still want to check out, and as soon as I do, I will do a post on it, maybe baked with a NoSQL db or something like that.
Cheers!
Resources: