Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Hands-On RESTful Python Web Services

You're reading from   Hands-On RESTful Python Web Services Develop RESTful web services or APIs with modern Python 3.7

Arrow left icon
Product type Paperback
Published in Dec 2018
Publisher
ISBN-13 9781789532227
Length 500 pages
Edition 2nd Edition
Languages
Tools
Concepts
Arrow right icon
Author (1):
Arrow left icon
Gaston C. Hillar Gaston C. Hillar
Author Profile Icon Gaston C. Hillar
Gaston C. Hillar
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Developing RESTful APIs and Microservices with Flask 1.0.2 FREE CHAPTER 2. Working with Models, SQLAlchemy, and Hyperlinked APIs in Flask 3. Improving Our API and Adding Authentication to it with Flask 4. Testing and Deploying an API in a Microservice with Flask 5. Developing RESTful APIs with Django 2.1 6. Working with Class-Based Views and Hyperlinked APIs in Django 2.1 7. Improving Our API and Adding Authentication to it with Django 8. Throttling, Filtering, Testing, and Deploying an API with Django 2.1 9. Developing RESTful APIs with Pyramid 1.10 10. Developing RESTful APIs with Tornado 5.1.1 11. Working with Asynchronous Code, Testing, and Deploying an API with Tornado 12. Assessment 13. Other Books You May Enjoy

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 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 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.

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 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

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.

You have been reading a chapter from
Hands-On RESTful Python Web Services - Second Edition
Published in: Dec 2018
Publisher:
ISBN-13: 9781789532227
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image