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.
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 the id argument. The code calls the self.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 the NotificationModel instance whose id matches the specified id returned by the notification_manager.get_notification method. The get method uses the @marshal_with decorator, with notification_fields as an argument. The decorator will take the NotificationModel instance and apply the field filtering and output formatting specified in the notification_fields dictionary.
- delete: This method receives the ID of the notification that has to be deleted in the id argument. The code calls the self.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 the notification_manager.delete_notification method with the received ID as an argument to remove the NotificationModel instance from our data repository. Then, the code returns a tuple composed of an empty response body and a 204 No Content status code. Notice that the returned status code in the tuple is specified with HttpStatus.no_content_204.value because we want to return the value of the enumerable, which is 204. 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 the id argument. The code calls the self.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 the NotificationModel instance whose id matches the specified id returned by the notification_manager.get_notification method in the notification variable. The next line creates a flask_restful.reqparse.RequestParser instance named parser. The RequestParser 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 the parser.add_argument method with the argument name and the type of the four arguments we want to parse. Then, the code calls the parser.parse_args method to parse all the arguments from the request and saves the returned dictionary (dict) in the args variable. The code updates all the attributes that have new values in the args dictionary in the NotificationModel instance, which is notification. 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 are None. The request doesn't need to include the four fields that can be updated with values. The code returns the updated notification. The patch method uses the @marshal_with decorator, with notification_fields as an argument. The decorator will take the NotificationModel instance, notification, and apply the field filtering and output formatting specified in the notification_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.
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 the NotificationModel instances saved in the notification_manager.notifications dictionary. The get method uses the @marshal_with decorator, with notification_fields as an argument. The decorator will take each NotificationModel instance in the returned list and apply the field filtering and output formatting specified in notification_fields.
- post: This method creates a flask_restful.reqparse.RequestParser instance named parser. The RequestParser instance allows us to add arguments with their names and types and then easily parse the arguments received with the POST request to create a new NotificationModel instance. The code makes three calls to parser.add_argument, with the argument name and the type of the three arguments we want to parse. Then, the code calls the parser.parse_args method to parse all the arguments from the request and saves the returned dictionary (dict) in the args variable. The code uses the parsed arguments in the dictionary to specify the values for the message, ttl, and notification_category attributes to create a new NotificationModel instance and save it in the notification variable. The value for the creation_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 the notification_manager.insert_notification method with the new NotificationModel instance (notification) to add this new instance to the dictionary. The post method uses the @marshal_with decorator with notification_fields as an argument. The decorator will take the recently created and stored NotificationModel instance, notification, and apply the field filtering and output formatting specified in notification_fields. Then, the code returns a tuple composed of the inserted NotificationModel instance and a 201 Created status code. Notice that the returned status code in the tuple is specified with HttpStatus.created_201.value because we want to return the value of the enumerable, which is 201. We used multiple return values in the tuple to set the response code.
The following table shows the method of our classes created previously that we want to be executed for each combination of HTTP verb and scope:
HTTP verb |
Scope |
Class and method |
GET |
Collection of notifications |
NotificationList.get |
GET |
Notification |
Notification.get |
POST |
Collection of notifications |
NotificationList.post |
PATCH |
Notification |
Notification.patch |
DELETE |
Notification |
Notification.delete |