Chapter 5. Developing RESTful APIs with Flask
In this chapter, we will start working with Flask and its Flask-RESTful extension; we will also create a RESTful Web API that performs CRUD operations on a simple list. We will:
Design a RESTful API that performs CRUD operations in Flask with the Flask-RESTful extension
Understand the tasks performed by each HTTP method
Set up the virtual environment with Flask and its Flask-RESTful extension
Declare status codes for the responses
Create the model to represent a resource
Use a dictionary as a repository
Configure output fields for serialized responses
Work with resourceful routing on top of Flask pluggable views
Configure resource routing and endpoints
Make HTTP requests to the Flask API
Work with command-line tools to interact with the Flask API
Work with GUI tools to interact with the Flask API
Designing a RESTful API to interact with a simple data source
Imagine that we have to configure the messages to be displayed in an OLED display wired to an IoT (Internet of Things) device, the IoT device is capable of running Python 3.5, Flask, and other Python packages. There is a team that is writing code that retrieves string messages from a dictionary and displays them in the OLED display wired to the IoT device. We have to start working on a mobile app and a website that has to interact with a RESTful API to perform CRUD operations with string messages.
We don't need an ORM because we won't persist the string messages on a database. We will just work with an in-memory dictionary as our data source. It is one of the requirements for this RESTful API. In this case, the RESTful web service will be running on the IoT device, that is, we will run the Flask development server on the IoT device.
Tip
We will definitely lose scalability for our RESTful API because we have the in-memory data source...
Understanding the tasks performed by each HTTP method
Let's consider that http://localhost:5000/api/messages/
is the URL for the collection of messages. If we add a number to the preceding URL, we identify a specific message whose id is equal to the specified numeric value. For example, http://localhost:5000/api/messsages/6
identifies the message whose id is equal to 6
.
Tip
We want our API to be able to differentiate collections from a single resource of the collection in the URLs. When we refer a collection, we will use a slash (/
) as the last character for the URL, as in http://localhost:5000/api/messages/
. When we refer to a single resource of the collection we won't use a slash (/
) as the last character for the URL, as in http://localhost:5000/api/messages/6
.
We have to compose and send an HTTP request with the POST
HTTP verb and the http://localhost:5000/api/messages/
request URL to create a new message. In addition, we have to provide the JSON key-value pairs with the field names and...
Setting up a virtual environment with Flask and Flask-RESTful
In Chapter 1
,
Developing RESTful APIs with Django, we learned that, throughout this book, we were going to work with the lightweight virtual environments introduced in Python 3.4 and improved in Python 3.4. Now, we will follow the steps to create a new lightweight virtual environment to work with Flask and Flask-RESTful. It is highly recommended to read
Chapter 1,
Developing RESTful APIs with Django, in case you don't have experience with lightweight virtual environments in Python. The chapter includes all the detailed explanations of the effects of the steps we are going to follow.
First, we have to select the target folder or directory for our virtual environment. We will use the following path in the example for macOS and Linux. The target folder for the virtual environment will be the PythonREST/Flask01
folder within our home directory. For example, if our home directory in macOS or Linux is /Users/gaston
, the virtual environment...
Declaring status codes for the responses
Neither Flask nor Flask-RESTful includes the declaration of variables for the different HTTP status codes. We don't want to return numbers as status codes. We want our code to be easy to read and understand, and therefore, we will use descriptive HTTP status codes. We will borrow the code that declares useful functions and variables related to HTTP status codes from the status.py
file included in Django REST Framework, that is, the framework we have been using in the preceding chapters.
First, create a folder named api
within the root folder for the recently created virtual environment, and then create a new status.py
file within the api
folder. The following lines show the code that declares functions and variables with descriptive HTTP status codes in the api/models.py
file borrowed from the rest_framework.status
module. We don't want to reinvent the wheel, and the module provides everything we need to work with HTTP status codes in our Flask-based...
Now, we will create a simple MessageModel
class that we will use to represent messages. Remember that we won't be persisting the model in the database, and therefore, in this case, our class will just provide the required attributes and no mapping information. Create a new models.py
file in the api
folder. The following lines show the code that creates a MessageModel
class in the api/models.py
file. The code file for the sample is included in the restful_python_chapter_05_01
folder:
class MessageModel:
def __init__(self, message, duration, creation_date, message_category):
# We will automatically generate the new id
self.id = 0
self.message = message
self.duration = duration
self.creation_date = creation_date
self.message_category = message_category
self.printed_times = 0
self.printed_once = False
The MessageModel
class just declares a constructor, that is, the __init__
method. This method receives...
Using a dictionary as a repository
Now, we will create a MessageManager
class that we will use to persist the MessageModel
instances in an in-memory dictionary. Our API methods will call methods for the MessageManager
class to retrieve, insert, update, and delete MessageModel
instances. Create a new api.py
file in the api
folder. The following lines show the code that creates a MessageManager
class in the api/api.py
file. In addition, the following lines declare all the imports
we will need for all the code we will write in this file. The code file for the sample is included in the restful_python_chapter_05_01
folder.
from flask import Flask
from flask_restful import abort, Api, fields, marshal_with, reqparse, Resource
from datetime import datetime
from models import MessageModel
import status
from pytz import utc
class MessageManager():
last_id = 0
def __init__(self):
self.messages = {}
def insert_message(self, message):
self.__class__.last_id...
Configuring output fields
Now, we will create a message_fields
dictionary that we will use to control the data that we want Flask-RESTful to render in our response, when we return MessageModel
instances. Open the previously created api/api.py
file and add the following lines. The code file for the sample is included in the restful_python_chapter_05_01
folder.
message_fields = {
'id': fields.Integer,
'uri': fields.Url('message_endpoint'),
'message': fields.String,
'duration': fields.Integer,
'creation_date': fields.DateTime,
'message_category': fields.String,
'printed_times': fields.Integer,
'printed_once': fields.Boolean
}
message_manager = MessageManager()
We declared the message_fields
dictionary (dict
) with key-value pairs of strings and classes declared in the flask_restful.fields
module. The keys are the names of the attributes we want to render from the MessageModel
class and the values are the classes that format and return the value for...
Working with resourceful routing on top of Flask pluggable views
Flask-RESTful uses resources built on top of Flask pluggable views as the main building block for a RESTful API. We just need to create a subclass of the flask_restful.Resource
class and declare the methods for each supported HTTP verb. A subclass of flask_restful.Resource
represents a RESTful resource and therefore, we will have to declare one class to represent the collection of messages and another one to represent the message resource.
First, we will create a Message
class that we will use to represent the message resource. Open the previously created api/api.py
file and add the following lines. The code file for the sample is included in the restful_python_chapter_05_01
folder, as shown:
class Message(Resource):
def abort_if_message_doesnt_exist(self, id):
if id not in message_manager.messages:
abort(
status.HTTP_404_NOT_FOUND,
message="Message {0} doesn't exist...
Configuring resource routing and endpoints
We must make the necessary resource routing configurations to call the appropriate methods and pass them all the necessary arguments by defining URL rules. The following lines create the main entry point for the application, initialize it with a Flask application and configure the resource routing for the api
. Open the previously created api/api.py
file and add the following lines. The code file for the sample is included in the restful_python_chapter_05_01
folder:
app = Flask(__name__)
api = Api(app)
api.add_resource(MessageList, '/api/messages/')
api.add_resource(Message, '/api/messages/<int:id>', endpoint='message_endpoint')
if __name__ == '__main__':
app.run(debug=True)
The code creates an instance of the flask_restful.Api
class and saves it in the api
variable. Each call to the api.add_resource
method routes a URL to a resource, specifically to one of the previously declared subclasses of the flask_restful.Resource
class...
Making HTTP requests to the Flask API
Now, we can run the api/api.py
script that launches Flask's development server to compose and send HTTP requests to our unsecure and simple Web API (we will definitely add security later). Execute the following command.
python api/api.py
The following lines show the output after we execute the previous command. The development server is listening at port 5000
.
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 294-714-594
With the previous command, we will start Flask development server and we will only be able to access it in our development computer. The previous command starts the development server in the default IP address, that is, 127.0.0.1
(localhost
). It is not possible to access this IP address from other computers or devices connected on our LAN. Thus, if we want to make HTTP requests to our API from other computers or devices connected to our LAN, we should use...
In this chapter, we designed a RESTful API to interact with a simple dictionary that acted as a data repository and perform CRUD operations with messages. We defined the requirements for our API and we understood the tasks performed by each HTTP method. We set up a virtual environment with Flask and Flask-RESTful.
We created a model to represent and persist messages. We learned to configure serialization of messages into JSON representations with the features included in Flask-RESTful. We wrote classes that represent resources and process the different HTTP requests and we configured the URL patterns to route URLs to classes.
Finally, we started Flask development server and we used command-line tools to compose and send HTTP requests to our RESTful API and analyzed how each HTTP request was processed in our code. We also worked with GUI tools to compose and send HTTP requests.
Now that we understand the basics of the combination of Flask and Flask-RESTful to create RESTful APIs, we...