Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Flask Web and API Development

You're reading from   Mastering Flask Web and API Development Build and deploy production-ready Flask apps seamlessly across web, APIs, and mobile platforms

Arrow left icon
Product type Paperback
Published in Aug 2024
Publisher Packt
ISBN-13 9781837633227
Length 494 pages
Edition 1st Edition
Languages
Tools
Concepts
Arrow right icon
Author (1):
Arrow left icon
Sherwin John C. Tragura Sherwin John C. Tragura
Author Profile Icon Sherwin John C. Tragura
Sherwin John C. Tragura
Arrow right icon
View More author details
Toc

Table of Contents (18) Chapters Close

Preface 1. Part 1:Learning the Flask 3.x Framework
2. Chapter 1: A Deep Dive into the Flask Framework FREE CHAPTER 3. Chapter 2: Adding Advanced Core Features 4. Chapter 3: Creating REST Web Services 5. Chapter 4: Utilizing Flask Extensions 6. Part 2:Building Advanced Flask 3.x Applications
7. Chapter 5: Building Asynchronous Transactions 8. Chapter 6: Developing Computational and Scientific Applications 9. Chapter 7: Using Non-Relational Data Storage 10. Chapter 8: Building Workflows with Flask 11. Chapter 9: Securing Flask Applications 12. Part 3:Testing, Deploying, and Building Enterprise-Grade Applications
13. Chapter 10: Creating Test Cases for Flask 14. Chapter 11: Deploying Flask Applications 15. Chapter 12: Integrating Flask with Other Tools and Frameworks 16. Index 17. Other Books You May Enjoy

Creating routes and navigations

Routing is a mapping of URL pattern(s) and other related details to a view function that’s done using Flask’s route decorators. On the other hand, the view function is a transaction that processes an incoming request from the clients and, at the same time, returns the necessary response to them. It follows a life cycle and returns an HTTP status as part of its response.

There are different approaches to assigning URL patterns to view functions. These include creating static and dynamic URL patterns, mapping URLs externally, and mapping multiple URLs to a view function.

Creating static URLs

Flask has several built-in route decorators that implement some of its components, and @route decorator is one of these. @route directly maps the URL address to the view function seamlessly. For instance, @route maps the index() view function presented in the project’s main.py file to the root URL or /, which makes index() the view function of the root URL.

But @route can map any valid URL pattern to any view function. A URL pattern is accepted if it follows the following best practices:

  • All characters must be in lowercase.
  • Use only forward slashes to establish site hierarchy.
  • URL names must be concise, clear, and within the business context.
  • Avoid spaces and special symbols and characters as much as possible.

The following home() view function renders an introductory page of our ch01 application and uses the URL pattern of /home for its access:

@app.route('/home')
def home():
    return '''
       <html><head><title>Online Personal … System</title>
          </head><body>
           <h1>Online … Counseling System (OPCS)</h1>
           <p>This is a template of a web-based counseling
              application where counselors can … … …</em>
           </body></html>
       '''

Now, Flask accepts simple URLs such as /home or complex ones with slashes and path-like hierarchy, including these multiple URLs.

Assigning multiple URLs

A view function can have a stack of @route decorators annotated on it. Flask allows us to map these valid multiple URLs if there is no conflict with other view functions and within that stack of @route mappings. The following version of the home() view function now has three URLs, which means any of these addresses can render the home page:

@app.route('/home')
@app.route('/information')
@app.route('/introduction')
def home():
    return '''<html><head>
             <title>Online Personal … System</title>
        </head><body>
           <h1>Online … Counseling System (OPCS)</h1>
            … … … … …
        </body></html>
       '''

Aside from complex URLs, Flask is also capable of creating dynamic routes.

Applying path variables

Adding path variables makes a URL dynamic and changeable depending on the variations of the values passed to it. Although some SEO experts may disagree with having dynamic URLs, the Flask framework can allow view functions with changeable URL patterns to be implemented.

In Flask, a path variable is declared inside a diamond operator (<>) and placed within the URL path. The following view function has a dynamic URL with several path variables:

@app.route('/exam/passers/list/<float:rate>/<uuid:docId>')
def report_exam_passers(rating:float, docId:uuid4 = None):
    exams = list_passing_scores(rating)
    response = make_response(
      render_template('exam/list_exam_passers.html',
           exams=exams, docId=docId), 200)
    return response

As we can see, path variables are identified with data types inside the diamond operator (<>) using the <type:variable> pattern. These parameters are set to None if the path variables are optional. The path variable is considered a string type by default if it has no associated type hint. Flask 3.x offers these built-in data types for path variables:

  • string: Allows all valid characters except for slashes.
  • int: Takes integer values.
  • float: Accepts real numbers.
  • uuid: Takes unique 32 hexadecimal digits that are used to identify or represent records, documents, hardware gadgets, software licenses, and other information.
  • path: Fetches characters, including slashes.

These path variables can’t function without the corresponding parameters of the same name and type declared in the view function’s parameter list. In the previous report_exam_passers() view function, the local rating and docId parameters are the variables that will hold the values of the path variables, respectively.

But there are particular or rare cases where path variables should be of a type different than the supported ones. View functions with path variables declared as list, set, date, or time will throw Status Code 500 in Flask. As a workaround, the Werkzeug bundle of libraries offers a BaseConverter utility class that can help customize a variable type for paths that allows other types to be part of the type hints. The following view function requires a date type hint to generate a certificate in HTML format:

@app.route('/certificate/accomp/<string:name>/  <string:course>/<date:accomplished_date>')
def show_certification(name:str, course:str, accomplished_date:date):
    certificate = """<html><head>
          <title>Certificate of Accomplishment</title>
         </head><body>
           <h1>Certificate of Accomplishment</h1>
           <p>The participant {} is, hereby awarded this certificate of accomplishment, in {} course on {} date for passing all exams. He/she proved to be ready for any of his/her future endeavors.</em>
         </body></html>
    """.format(name, course, accomplished_date)
    return certificate, 200

accomplished_date in show_certification() is a date hint type and will not be valid until the following tasks are implemented:

  • First, subclass BaseConverter from the werkzeug.routing module. In the /converter package of this project, there is a module called date_converter.py that implements our date hint type, as shown in the following code:
    from werkzeug.routing import BaseConverter
    from datetime import datetime
    class DateConverter(BaseConverter):
       def to_python(self, value):
         date_value = datetime.strptime(value, "%Y-%m-%d")
         return date_value

    The given DateConverter will custom-handle date variables within our Flask application.

  • BaseConverter has a to_python() method that must be overridden to implement the necessary conversion process. In the case of DateConverter, we need strptime() so that we can convert the path variable value in the yyyy-mm-dd format into the datetime type.
  • Lastly, declare our new custom converter in the Flask instance of the main.py module. The following snippet registers DateConverter to app:
    app = Flask(__name__)
    app.url_map.converters['date'] = DateConverter

After following all these steps, the custom path variable type – for instance, date – can now be utilized across the application.

Assigning URLs externally

There is also a way to implement a routing mechanism without using the @route decorator, and that’s by utilizing Flask’s add_url_rule() method to register views. This approach binds a valid request handler to a unique URL pattern for every call to add_url_rule() of the app instance in the main.py module, not in the handler’s module scripts, thus making this approach an external way of building routes. The following arguments are needed by the add_url_rule() method to perform mapping:

  • The URL pattern with or without the path variables.
  • The URL name and, usually, the exact name of the view function.
  • The view function itself.

The invocation of this method must be in the main.py file, anywhere after its @route implementations and view imports. The following main.py snippet shows the external route mapping of the show_honor_dismissal() view function to its dynamic URL pattern. This view function generates a termination letter for the counseling and consultation agreement between a clinic and a patient:

app = Flask(__name__)
def show_honor_dissmisal(counselor:str, effective_date:date, patient:str):
    letter = """
       … … … … …
       </head><body>
           <h1> Termination of Consultation </h1>
           <p>From: {}
           <p>Head, Counselor
           <p>Date: {}
           <p>To: {}
           <p>Subject: Termination of consultation
                    <p>Dear {},
                    … … … … … …
                    <p>Yours Sincerely,
                    <p>{}
                </body>
            </html>
    """.format(counselor, effective_date, patient, patient, counselor)
    return letter, 200
app.add_url_rule('/certificate/terminate/<string:counselor>/<date:effective_date>/<string:patient>', 'show_honor_dissmisal', views.certificates.show_honor_dissmisal)

Binding URL mappings to views using add_url_rule() is not only confined to the decorated function views but is also necessary for class-based views.

Implementing class-based views

Another way to create the view layer is through Flask’s class-based view approach. Unlike the Django framework, which uses mixin programming to implement its class-based views, Flask provides two API classes, namely View and MethodView, that can directly subclass any custom view implementations.

The most common and generic class to implement HTTP GET operations is the View class from the flask.views module. It has a dispatch_request() method that executes the request-response transactions like a typical view function. Thus, subclasses must override this core method to implement their view transactions. The following class, ListUnpaidContractView, renders a list of patients with payments due to the clinic:

from flask.views import View
class ListUnpaidContractView(View):
    def dispatch_request(self):
        contracts = select_all_unpaid_patient()
        return render_template("contract/ list_patient_contract.html", contracts=contracts)

select_all_unpaid_patient() will provide the patient records from the database. All these records will be rendered to the list_patient_contract.html template. Now, aside from overriding the dispatch_request() method, ListUnpaidContractView also inherits all the attributes and helper methods from the View class, including the as_view() static method, which creates a view name for the view. During view registration, this view name will serve as the view_func name of the custom View class in the add_url_rule() method with its mapped URL pattern. The following main.py snippet shows how to register ListUnpaidContractView:

app.add_url_rule('/contract/unpaid/patients', view_func=ListUnpaidContractView.as_view('list-unpaid-view'))

If a View subclass needs an HTTP POST transaction, it has a built-class class attribute called methods that accepts a list of HTTP methods the class needs to support. Without it, the default is the [ "GET" ] value. Here is another custom View class of our Online Personal Counselling System app that deletes existing patient contracts of the clinic:

class DeleteContractByPIDView(View):
    methods = ['GET', 'POST']
    … … … … … …
    def dispatch_request(self):
       if request.method == "GET":
          pids = list_pid()
          return render_template("contract/ delete_patient_contract.html", pids=pids)
       else:
          pid = int(request.form['pid'])
          result = delete_patient_contract_pid(pid)
          if result == False:
               pids = list_pid()
               return render_template("contract/ delete_patient_contract.html", pids=pids)
          contracts = select_all_patient_contract()
          return render_template("contract/ list_patient_contract.html", contracts=contracts)

DeleteContractByPIDView handles a typical form-handling transaction, which has both a GET operation for loading the form page and a POST operation to manage the submitted form data. The POST operation will verify if the patient ID submitted by the form page exists, and it will eventually delete the contract(s) of the patient using the patient ID and render an updated list of contracts.

Other than the View class, an alternative API that can also build view transactions is the MethodView class. This class is suitable for web forms since it has the built-in GET and POST hints or templates that subclasses need to define but without the need to identify the GET transactions from POST, like in a view function. Here is a view that uses MethodView to manage the contracts of the patients in the clinic:

from flask.views import MethodView
class ContractView(MethodView):
    … … … … … …
    def get(self):
        return render_template("contract/ add_patient_contract.html")
    def post(self):
        pid = request.form['pid']
        approver = request.form['approver']
        … … … … … …
        result = insert_patient_contract(pid=int(pid), approved_by=approver, approved_date=approved_date, hcp=hcp, payment_mode=payment_mode, amount_paid=float(amount_paid), amount_due=float(amount_due))
        if result == False:
          return render_template("contract/ add_patient_contract.html")
        contracts = select_all_patient_contract()
        return render_template("contract/ list_patient_contract.html", contracts=contracts)

The MethodView class does not have a methods class variable to indicate the HTTP methods supported by the view. Instead, the subclass can select the appropriate HTTP hints from MethodView, which will then implement the required HTTP transactions of the custom view class.

Since MethodView is a subclass of the View class, it also has an as_view() class method that creates a view_func name of the view. This is also necessary for add_url_rule() registration.

Aside from GET and POST, the MethodView class also provides the PUT, PATCH, and DELETE method hints for API-based applications. MethodView is better than the View API because it organizes the transactions according to HTTP methods and checks and executes these HTTP methods by itself at runtime. In general, between the decorated view function and the class-based ones, the latter approach provides a complete Flask view component because of the attributes and built-in methods inherited by the view implementation from these API classes. Although the decorated view function can support a flexible and open-ended strategy for scalable applications, it cannot provide an organized base functionality that can supply baseline view features to other related views, unlike in a class-based approach. However, the choice still depends on the scope and requirements of the application.

Now that we’ve created and registered the routes, let’s scrutinize these view implementations and identify the essential Flask components that compose them.

You have been reading a chapter from
Mastering Flask Web and API Development
Published in: Aug 2024
Publisher: Packt
ISBN-13: 9781837633227
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