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".format(id)) 
 
    @marshal_with(message_fields) 
    def get(self, id): 
        self.abort_if_message_doesnt_exist(id) 
        return message_manager.get_message(id) 
 
    def delete(self, id): 
        self.abort_if_message_doesnt_exist(id) 
        message_manager.delete_message(id) 
        return '', status.HTTP_204_NO_CONTENT 
 
    @marshal_with(message_fields) 
    def patch(self, id): 
        self.abort_if_message_doesnt_exist(id) 
        message = message_manager.get_message(id) 
        parser = reqparse.RequestParser() 
        parser.add_argument('message', type=str) 
        parser.add_argument('duration', type=int) 
        parser.add_argument('printed_times', type=int) 
        parser.add_argument('printed_once', type=bool) 
        args = parser.parse_args() 
        if 'message' in args: 
            message.message = args['message'] 
        if 'duration' in args: 
            message.duration = args['duration'] 
        if 'printed_times' in args: 
            message.printed_times = args['printed_times'] 
        if 'printed_once' in args: 
            message.printed_once = args['printed_once'] 
        return message 

The Message class is a subclass of flask_restful.Resource 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 message that has to be retrieved in the id argument. The code calls the self.abort_if_message_doesnt_exist method to abort in case there is no message with the requested id. In case the message exists, the code returns the MessageModel instance whose id that matches the specified id returned by the message_manager.get_message method. The get method uses the @marshal_with decorator with message_fields as an argument. The decorator will take the MessageModel instance and apply the field filtering and output formatting specified in message_fields.
  • delete: This method receives the id of the message that has to be deleted in the id argument. The code calls the self.abort_if_message_doesnt_exist method to abort, in case there is no message with the requested id. In case the ```message exists, the code calls the message_manager.delete_message method with the received id as an argument to remove the MessageModel instance from our data repository. Then, the code returns an empty response body and a 204 No Content status code.
  • patch: This method receives the id of the message that has to be updated or patched in the id argument. The code calls the self.abort_if_message_doesnt_exist method to abort in case there is no message with the requested id. In case the message exists, the code saves the MessageModel instance whose id that matches the specified id returned by the message_manager.get_message method in the message 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 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 MessageModel instance: message. In case the request didn't include values for certain fields, the code won't make changes to the realted attributes. The request doesn't require to include the four fields that can be updated with values. The code returns the updated message. The patch method uses the @marshal_with decorator with message_fields as an argument. The decorator will take the MessageModel instance, message, and apply the field filtering and output formatting specified in message_fields.

Tip

We used multiple return values to set the response code.

As previously explained, the three methods call the internal abort_if_message_doesnt_exist method that receives the id for an existing MessageModel instance in the id argument. If the received id is not present in the keys of the message_manager.messages dictionary, the method calls the flask_restful.abort function with status.HTTP_404_NOT_FOUND as the http_status_code argument and a message indicating that the message with the specified id doesn't exists. The abort function raises an HTTPException 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 that takes a single data object or a list of data objects and applies the field filtering and output formatting specifies as an argument. The marshalling can also work with dictionaries (dicts). In both methods, we specified message_fields as an argument, and therefore, the code renders the following fields: id, uri, message, duration, creation_date, message_category, printed_times and printed_once. When we use the @marshal_with decorator, we are automatically returning an HTTP 200 OK status code.

The following return statement with the @marshal_with(message_fields) decorator returns an HTTP 200 OK status code because we didn't specify any status code after the returned object (message):

return message 

The next line is the line of code that is really executed with the @marshal_with(message_fields) decorator, and we can use it instead of working with the decorator:

return marshal(message, resource_fields), status.HTTP_200_OK 

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 MessageList class that we will use to represent the collection of messages. 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:

class MessageList(Resource): 
    @marshal_with(message_fields) 
    def get(self): 
        return [v for v in message_manager.messages.values()] 
 
    @marshal_with(message_fields) 
    def post(self): 
        parser = reqparse.RequestParser() 
        parser.add_argument('message', type=str, required=True, help='Message cannot be blank!') 
        parser.add_argument('duration', type=int, required=True, help='Duration cannot be blank!') 
        parser.add_argument('message_category', type=str, required=True, help='Message category cannot be blank!') 
        args = parser.parse_args() 
        message = MessageModel( 
            message=args['message'], 
            duration=args['duration'], 
            creation_date=datetime.now(utc), 
            message_category=args['message_category'] 
            ) 
        message_manager.insert_message(message)  
        return message, status.HTTP_201_CREATED 

The MessageList class is a subclass of flask_restful.Resource and declares the following two methods that will be called when the HTTP method with the same name arrives as a request on the represented resource:

  • get: This method returns a list with all the MessageModel instances saved in the message_manager.messages dictionary. The get method uses the @marshal_with decorator with message_fields as an argument. The decorator will take each MessageModel instance in the returned list and apply the field filtering and output formatting specified in message_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 MessageModel instance. The code makes three calls to the 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, duration and message_category attributes to create a new MessageModel instance and save it in the message variable. The value for the creation_date argument is set to the current datetime with time zone info, and therefore, it isn't parsed from the request. Then, the code calls the message_manager.insert_message method with the new MessageModel instance (message) to add this new instance to the dictionary. The post method uses the @marshal_with decorator with message_fields as an argument. The decorator will take the recently created and stored MessageModel instance, message, and apply the field filtering and output formatting specified in message_fields. The code returns an HTTP 201 Created status code.

The following table shows the method of our previously created classes that we want to be executed for each combination of HTTP verb and scope:

HTTP verb

Scope

Class and method

GET

Collection of messages

MessageList.get

GET

Message

Message.get

POST

Collection of messages

MessageList.post

PATCH

Message

Message.patch

DELETE

Message

Message.delete

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.164.141