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
.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 |
|
Collection of messages |
MessageList.get |
|
Message |
Message.get |
|
Collection of messages |
MessageList.post |
|
Message |
Message.patch |
|
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.
18.222.164.141