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.
Note
A subclass of flask_restful.Resource
represents a RESTful resource and, therefore, we will have to declare one class to represent the collection of notifications and another one to represent the notification resource.
First, we will create a Notification
class that we will use to represent the notification resource. Open the service/service.py
file created previously and add the following lines. The code file for the sample is included in the restful_python_2_01_01
folder, in the Flask01/service/service.py
file:
class Notification(Resource): def abort_if_notification_not_found(self, id): if id not in notification_manager.notifications: abort( HttpStatus.not_found_404.value, message="Notification {0} doesn't exist".format(id)) @marshal_with(notification_fields)def get(self, id): self.abort_if_notification_not_found(id) return notification_manager.get_notification(id) def delete(self, id): self.abort_if_notification_not_found(id) notification_manager.delete_notification(id) return '', HttpStatus.no_content_204.value @marshal_with(notification_fields) def patch(self, id): self.abort_if_notification_not_found(id) notification = notification_manager.get_notification(id) parser = reqparse.RequestParser() parser.add_argument('message', type=str) parser.add_argument('ttl', type=int) parser.add_argument('displayed_times', type=int) parser.add_argument('displayed_once', type=bool) args = parser.parse_args() print(args) if 'message' in args and args['message'] is not None: notification.message = args['message'] if 'ttl' in args and args['ttl'] is not None: notification.ttl = args['ttl'] if 'displayed_times' in args and args['displayed_times'] is not None: notification.displayed_times = args['displayed_times'] if 'displayed_once' in args and args['displayed_once'] is not None: notification.displayed_once = args['displayed_once'] return notification
The Notification
class is a subclass of the flask_restful.Resource
superclass and declares the following three methods that will be called when the HTTP method with the same name arrives as a request on the represented resource:
get
: This method receives the ID of the notification that has to be retrieved in theid
argument. The code calls theself.abort_if_notification_not_found
method to abort in case there is no notification with the requested ID. In case the notification exists, the code returns theNotificationModel
instance whoseid
matches the specifiedid
returned by thenotification_manager.get_notification
method. Theget
method uses the@marshal_with
decorator, withnotification_fields
as an argument. The decorator will take theNotificationModel
instance and apply the field filtering and output formatting specified in thenotification_fields
dictionary.delete
: This method receives the ID of the notification that has to be deleted in theid
argument. The code calls theself.abort_if_notification_not_found
method to abort in case there is no notification with the requested ID. In case the notification exists, the code calls thenotification_manager.delete_notification
method with the received ID as an argument to remove theNotificationModel
instance from our data repository. Then, the code returns a tuple composed of an empty response body and a204 No Content
status code. Notice that the returned status code in the tuple is specified withHttpStatus.no_content_204.value
because we want to return the value of the enumerable, which is204
. We used multiple return values in the tuple to set the response code.patch
: This method receives the ID of the notification that has to be updated or patched in theid
argument. The code calls theself.abort_if_notification_not_found
method to abort in case there is no notification with the requested ID. In case the notification exists, the code saves theNotificationModel
instance whoseid
matches the specifiedid
returned by thenotification_manager.get_notification
method in thenotification
variable. The next line creates aflask_restful.reqparse.RequestParser
instance namedparser
. TheRequestParser
instance allows us to add arguments with their names and types and then easily parse the arguments received with the request. The code makes four calls to theparser.add_argument
method with the argument name and the type of the four arguments we want to parse. Then, the code calls theparser.parse_args
method to parse all the arguments from the request and saves the returned dictionary (dict
) in theargs
variable. The code updates all the attributes that have new values in theargs
dictionary in theNotificationModel
instance, which isnotification
. In case the request didn't include values for certain fields, the code won't make changes to the related attributes because the code doesn't consider the values that areNone
. The request doesn't need to include the four fields that can be updated with values. The code returns the updatednotification
. Thepatch
method uses the@marshal_with
decorator, withnotification_fields
as an argument. The decorator will take theNotificationModel
instance,notification
, and apply the field filtering and output formatting specified in thenotification_fields
dictionary.
As previously explained, the three methods call the internal abort_if_notification_not_found
method, which receives the ID for an existing NotificationModel
instance in the id
argument. If the received id
is not in the keys of the notification_manager.notifications
dictionary, the method calls the flask_restful.abort
function with HttpStatus.not_found_404.value
as the http_status_code
argument and a message indicating that the notification with the specified ID doesn't exist. The abort
function raises an HTTPException
exception for the received http_status_code
and attaches the additional keyword arguments to the exception for later processing. In this case, we generate an HTTP 404 Not Found
status code.
Both the get
and patch
methods use the @marshal_with
decorator, which takes a single data object or a list of data objects, and applies the field filtering and output formatting specified as an argument. The marshalling can also work with dictionaries (dict
). In both methods, we specified notification_fields
as an argument and, therefore, the code renders the following fields: id
, uri
, message
, ttl
, creation_date
, notification_category
, displayed_times
, and displayed_once
.
Note
Whenever we use the @marshal_with
decorator, we are automatically returning an HTTP 200 OK
status code.
The following return
statement with the @marshal_with(notification_fields)
decorator returns an HTTP 200 OK
status code because we didn't specify any status code after the returned object (notification
):
return notification
The next line is the code that is actually executed with the @marshal_with(notification_fields)
decorator and we can use it instead of working with the decorator:
return marshal(notification, resource_fields), HttpStatus. HttpStatus.ok_200.value
For example, we can call the marshal
function as shown in the previous line, instead of using the @marshal_with
decorator, and the code will produce the same result.
Now, we will create a NotificationList
class that we will use to represent the collection of notifications. Open the service/service.py
file created previously and add the following lines.
The code file for the sample is included in the restful_python_2_01_01
folder, in the Flask01/service/service.py
file:
class NotificationList(Resource): @marshal_with(notification_fields) def get(self): return [v for v in notification_manager.notifications.values()] @marshal_with(notification_fields) def post(self): parser = reqparse.RequestParser() parser.add_argument('message', type=str, required=True, help='Message cannot be blank!') parser.add_argument('ttl', type=int, required=True, help='Time to live cannot be blank!') parser.add_argument('notification_category', type=str, required=True, help='Notification category cannot be blank!') args = parser.parse_args() notification = NotificationModel( message=args['message'], ttl=args['ttl'], creation_date=datetime.now(utc), notification_category=args['notification_category'] ) notification_manager.insert_notification(notification) return notification, HttpStatus.created_201.value
The NotificationList
class is a subclass of the flask_restful.Resource
superclass and declares the following two methods that will be called when the HTTP method with the same name arrives as a request on the resource represented:
get
: This method returns a list with all theNotificationModel
instances saved in thenotification_manager.notifications
dictionary. Theget
method uses the@marshal_with
decorator, withnotification_fields
as an argument. The decorator will take eachNotificationModel
instance in the returned list and apply the field filtering and output formatting specified innotification_fields
.post
: This method creates aflask_restful.reqparse.RequestParser
instance namedparser
. TheRequestParser
instance allows us to add arguments with their names and types and then easily parse the arguments received with thePOST
request to create a newNotificationModel
instance. The code makes three calls toparser.add_argument
, with the argument name and the type of the three arguments we want to parse. Then, the code calls theparser.parse_args
method to parse all the arguments from the request and saves the returned dictionary (dict
) in theargs
variable. The code uses the parsed arguments in the dictionary to specify the values for themessage
,ttl
, andnotification_category
attributes to create a newNotificationModel
instance and save it in thenotification
variable. The value for thecreation_date
argument is set to the current date and time with time zone information, and therefore, it isn't parsed from the request. Then, the code calls thenotification_manager.insert_notification
method with the newNotificationModel
instance (notification
) to add this new instance to the dictionary. Thepost
method uses the@marshal_with
decorator withnotification_fields
as an argument. The decorator will take the recently created and storedNotificationModel
instance,notification
, and apply the field filtering and output formatting specified innotification_fields
. Then, the code returns a tuple composed of the insertedNotificationModel
instance and a201 Created
status code. Notice that the returned status code in the tuple is specified withHttpStatus.created_201.value
because we want to return the value of the enumerable, which is201
. We used multiple return values in the tuple to set the response code.
The following table shows the method of our classes createdpreviously that we want to be executed for each combination of HTTP verb and scope:
HTTP verb | Scope | Class and method |
| Collection of notifications |
|
| Notification |
|
| Collection of notifications |
|
| Notification |
|
| Notification |
|
Note
If the request results in the invocation of a resource with an unsupported HTTP method, Flask-RESTful will return a response with the HTTP 405 Method Not Allowed
status code.