Create a RESTfull API using Python and Flask (Part 2)
Summary From Part 1
In part 1, we created our working Flask Application and we got some knowledge about Flask.
In this part, we’re finally ready to implement a small API with data that we’ll define right in our application.
Let’s Go
Here we’ll add our data as a list of Python dictionaries.
Dictionaries in Python are group pairs of keys and values, like this:
d = {
<key>: <value>,
<key>: <value>,
.
.
.
<key>: <value>
}>>> MLB_team = {
... 'Colorado' : 'Rockies',
... 'Boston' : 'Red Sox',
... 'Minnesota': 'Twins',
... 'Milwaukee': 'Brewers',
... 'Seattle' : 'Mariners'
... }
You can check more about this here.
Let’s add some data (entries on ten music tracks) as a list of dictionaries to our code. Each dictionary will contain AlbumId, Bytes, Composer, GenreId, MediaTypeId, Milliseconds, Name, TrackId and UnitPrice for each track. Finally, we’ll add a new function: a route that will allow a visitor to access our data.
Replace our previous code in api.py
with the code below:
import flaskfrom flask import request, jsonifyapp = flask.Flask(__name__)app.config["DEBUG"] = True# Create some test data for our catalog in the form of a list of dictionaries.tracks = [{"AlbumId": 1,"Bytes": 11170334,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 343719,"Name": "For Those About To Rock (We Salute You)","TrackId": 1,"UnitPrice": 0.99},{"AlbumId": 2,"Bytes": 5510424,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 342562,"Name": "Balls to the Wall","TrackId": 2,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 3990994,"Composer": "F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 230619,"Name": "Fast As a Shark","TrackId": 3,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 4331779,"Composer": "F. Baltes, R.A. Smith-Diesel, S. Kaufman, U. Dirkscneider & W. Hoffman","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 252051,"Name": "Restless and Wild","TrackId": 4,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 6290521,"Composer": "Deaffy & R.A. Smith-Diesel","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 375418,"Name": "Princess of the Dawn","TrackId": 5,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6713451,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 205662,"Name": "Put The Finger On You","TrackId": 6,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 7636561,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 233926,"Name": "Let's Get It Up","TrackId": 7,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6852860,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 210834,"Name": "Inject The Venom","TrackId": 8,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6599424,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 203102,"Name": "Snowballed","TrackId": 9,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 8611245,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 263497,"Name": "Evil Walks","TrackId": 10,"UnitPrice": 0.99}]@app.route('/', methods=['GET'])def home():return '''<h1>Welcome to New Project</h1><p>A prototype API for distant reading of Music Albums and Playlists.</p>'''# A route to return all of the available entries in our catalog.@app.route('/api/v1/resources/tracks/all', methods=['GET'])def api_all():return jsonify(tracks)app.run()
Run the code (navigate to your api
folder in the command line and enter python api.py
). Once the server is running, visit our route URL to view the data in the catalog:
http://127.0.0.1:5000/api/v1/resources/tracks/all
You should see JSON output for the three entries in our test catalog like this.
In Flask, jsonify
function that allows us to convert lists and dictionaries to JSON format. Here our Music Track entries converted from a list of Python dictionaries to JSON before being returned to a user.
Now, we have created our simple API. But it is limited to get all tracks only. How can we get specific Resources from this API such as “AlbumID”? The next section, we’ll allow users to find track via more specific data, such as an entry’s ID.
Filter Resources
Here users can only view our entire database without filtering any specific data field. This will become a useless thing when we add more because it is not easy to filter thousands of records manually. So, we’ll add a function that allows users to filter their returned results using a more specific request.
Replace our previous code in api.py
with the code below:
import flaskfrom flask import request, jsonifyapp = flask.Flask(__name__)app.config["DEBUG"] = True# Create some test data for our catalog in the form of a list of dictionaries.tracks = [{"AlbumId": 1,"Bytes": 11170334,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 343719,"Name": "For Those About To Rock (We Salute You)","TrackId": 1,"UnitPrice": 0.99},{"AlbumId": 2,"Bytes": 5510424,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 342562,"Name": "Balls to the Wall","TrackId": 2,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 3990994,"Composer": "F. Baltes, S. Kaufman, U. Dirkscneider & W. Hoffman","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 230619,"Name": "Fast As a Shark","TrackId": 3,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 4331779,"Composer": "F. Baltes, R.A. Smith-Diesel, S. Kaufman, U. Dirkscneider & W. Hoffman","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 252051,"Name": "Restless and Wild","TrackId": 4,"UnitPrice": 0.99},{"AlbumId": 3,"Bytes": 6290521,"Composer": "Deaffy & R.A. Smith-Diesel","GenreId": 1,"MediaTypeId": 2,"Milliseconds": 375418,"Name": "Princess of the Dawn","TrackId": 5,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6713451,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 205662,"Name": "Put The Finger On You","TrackId": 6,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 7636561,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 233926,"Name": "Let's Get It Up","TrackId": 7,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6852860,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 210834,"Name": "Inject The Venom","TrackId": 8,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 6599424,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 203102,"Name": "Snowballed","TrackId": 9,"UnitPrice": 0.99},{"AlbumId": 1,"Bytes": 8611245,"Composer": "Angus Young, Malcolm Young, Brian Johnson","GenreId": 1,"MediaTypeId": 1,"Milliseconds": 263497,"Name": "Evil Walks","TrackId": 10,"UnitPrice": 0.99}]@app.route('/', methods=['GET'])def home():return '''<h1>Welcome to New Project</h1><p>A prototype API for distant reading of Music Albums and Playlists.</p>'''
# A route to return all of the available entries in our catalog.@app.route('/api/v1/resources/tracks/all', methods=['GET'])def api_all():return jsonify(tracks)@app.route('/api/v1/resources/tracks', methods=['GET'])def api_id():#Check ID and If no ID is provided, display an error in the browser.if 'id' in request.args:id = int(request.args['id'])else:return "Error: No id field provided. Please specify an id."# Empty Listresults = []# Check trackid in catalog and return the resultfor track in tracks:if track['TrackId'] == id:results.append(track)# Convert our list of python dictionaries to the JSON format.return jsonify(results)app.run()
Run the code (navigate to your api
folder in the command line and enter python api.py
). Once the server is running, visit the below URLs to test the new filtering capability:
http://127.0.0.1:5000/api/v1/resources/tracks?id=0
This will return you an Empty List, since there is no track for which the “TrackId” value is 0
http://127.0.0.1:5000/api/v1/resources/tracks?id=1
This will return you a JSON data entry like this:
http://127.0.0.1:5000/api/v1/resources/tracks?id=2
This will return you a JSON data entry like this:
http://127.0.0.1:5000/api/v1/resources/tracks?id=3
This will return you a JSON data entry like this:
Each of these should return a different entry. But ,
http://127.0.0.1:5000/api/v1/resources/tracks?id=11
this should return an empty list: []
, since there is no “TrackId” for which the id value is 11.
What is this?
In this code, we create a new function, called api_root
, with the @app.route
syntax that map the function to the path /api/v1/resources/tracks
.
When we access http://127.0.0.1:5000/api/v1/resources/tracks api_root
function will run. (If we access this link without providing an ID, it will give an error message like Error: No id field provided. Please specify an id.
).
Query Parameters
Query parameters are a defined set of parameters attached to the end of a URL. They are extensions of the URL that are used to help define specific content or actions based on the data being passed. To append query parameters to the end of a URL, a ‘?’ Is added followed immediately by a query parameter.
So, the id must be provided like this: ?id=1
.
This part of the code determines if there is a query parameter, like ?id=1
, and then assigns the provided ID to a variable. If there is not query parameter, it will return an Error Message.
if 'id' in request.args:
id = int(request.args['id'])
else:
return "Error: No id field provided. Please specify an id."
This section checks those tracks that have the provided Track ID, and appends them to the list that will be returned to the user:
for track in tracks:
if track['TrackId']== id:
results.append(track)
Finally, the return jsonify(results)
line takes the list of results and renders them in the browser as JSON.
Congratulations!!
You have created an actual API. In this tutorial, you implemented a small API with data using Python.
In Part 3 of this series, you’ll learn somewhat more complex API that uses a database.
Click here if you haven’t read PART 1