Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying Mastering Flask Web and API Development
  • Table Of Contents Toc
  • Feedback & Rating feedback
Mastering Flask Web and API Development

Mastering Flask Web and API Development

By : Sherwin John C. Tragura
5 (2)
close
close
Mastering Flask Web and API Development

Mastering Flask Web and API Development

5 (2)
By: Sherwin John C. Tragura

Overview of this book

Flask is a popular Python framework known for its lightweight and modular design. Mastering Flask Web and API Development will take you on an exhaustive tour of the Flask environment and teach you how to build a production-ready application. You’ll start by installing Flask and grasping fundamental concepts, such as MVC and ORM database access. Next, you’ll master structuring applications for scalability through Flask blueprints. As you progress, you’ll explore both SQL and NoSQL databases while creating REST APIs and implementing JWT authentication, and improve your skills in role-based access security, utilizing LDAP, OAuth, OpenID, and databases. The new project structure, managed by context managers, as well as ASGI support, has revolutionized Flask, and you’ll get to grips with these crucial upgrades. You'll also explore out-of-the-box integrations with technologies, such as RabbitMQ, Celery, NoSQL databases, PostgreSQL, and various external modules. The concluding chapters discuss enterprise-related challenges where Flask proves its mettle as a core solution. By the end of this book, you’ll be well-versed with Flask, seeing it not only as a lightweight web and API framework, but also as a potent problem-solving tool in your daily work, addressing integration and enterprise issues alongside Django and FastAPI.
Table of Contents (18 chapters)
close
close
1
Part 1:Learning the Flask 3.x Framework
6
Part 2:Building Advanced Flask 3.x Applications
12
Part 3:Testing, Deploying, and Building Enterprise-Grade Applications

Building the data layer with PostgreSQL

PostgreSQL is an object-relational database system, and Flask can utilize it as a data storage platform if the activated virtual environment has the psycopg2-binary extension module. To install this extension module into the venv, run the following command:

pip install psycopg2-binary

Now, we can write an approach to establish a connection to the PostgreSQL database.

Setting up database connectivity

There are multiple ways to create a connection to a database, but this chapter will showcase a Pythonic way to extract that connection using a custom decorator. In the project’s /config directory, there is a connect_db decorator that uses psycopgy2.connect() to establish connectivity to the opcs database of our prototype. Here is the implementation of this custom decorator:

import psycopg2
import functools
from os import environ
def connect_db(func):
    @functools.wraps(func)
    def repo_function(*args, **kwargs):
        conn = psycopg2.connect(
            host=environ.get('DB_HOST'),
            database=environ.get('DB_NAME'),
            port=environ.get('DB_PORT'),
            user = environ.get('DB_USER'),
            password = environ.get('DB_PASS'))
        resp = func(conn, *args, **kwargs)
        conn.commit()
        conn.close()
        return resp
    return repo_function

The given decorator provides the connection instance, conn, to a repository function and commits all the changes to the database after a transaction’s successful execution. Also, it will close the database connection at the end of the process. All the database details, such as DB_HOST, DB_NAME, and DB_PORT, are stored as environment variables inside a .env file. To retrieve them using the environ dictionary of the os module, run the following command to install the required extension:

pip install python-dotenv

However, there are other ways to manage these custom and built-in configuration variables instead of storing them as .env variables. The next topic will expound on this, but first, let’s apply @connect_db to our repository layer.

Implementing the repository layer

The following insert_signup() transaction adds a new user signup record to the database. It gets the conn instance from the @connect_db decorator. Our application has no object-relational mapper yet and solely depends on the psycopg2 driver to perform the CRUD operation. The cursor instance created by conn executes the INSERT statement of the following transaction with form data provided by its view function:

from config.db import connect_db
from typing import Dict, Any, List
@connect_db
def insert_signup(conn, user:str, passw:str, utype:str, fname:str, lname:str, cid:str) -> bool:
    try:
        cur = conn.cursor()
        sql = 'INSERT INTO signup (username, password, user_type, firstname, lastname, cid) VALUES (%s, %s, %s, %s, %s, %s)'
        values = (user, passw, utype, fname, lname, cid)
        cur.execute(sql, values)
        cur.close()
        return True
    except Exception as e:
        cur.close()
        print(e)
    return False

cursor is an object derived from conn that uses a database session to perform insert, update, delete, and fetch operations. So, just like insert_signup(), the following transaction uses cursor again to execute the UPDATE statement:

@connect_db
def update_signup(conn, id:int, details:Dict[str, Any]) -> bool:
    try:
        cur = conn.cursor()
        params = ['{} = %s'.format(key) for key in details.keys()]
        values = tuple(details.values())
        sql = 'UPDATE signup SET {} where id = {}'.format(', '.join(params), id);
        cur.execute(sql, values)
        cur.close()
        return True
    except Exception as e:
        cur.close()
        print(e)
    return False

To complete the CRUD operations for the signup table, here is the DELETE transaction from our application:

@connect_db
def delete_signup(conn, id) -> bool:
    try:
        cur = conn.cursor()
        sql = 'DELETE FROM signup WHERE id = %s'
        values = (id, )
        cur.execute(sql, values)
        cur.close()
        return True
    except Exception as e:
        cur.close()
        print(e)
    return False

The use of an ORM to build the model layer will be part of Chapter 2’s discussions. For now, the views and services of our application rely on a repository layer that manages PostgreSQL data directly through the psycopg2 driver.

After creating the repository layer, many applications can build a service layer to provide loose coupling between the CRUD operations and the views.

Creating the service layer

The service layer of the application builds the business logic of the view functions and the repository. Instead of loading the view functions with transaction-related and business processes, we place all these implementations in the service layer by creating lists of all the counselor and patient IDs, validating where to persist the newly approved user, and creating a list of patients who excelled in the examinations. The following service function evaluates and records patients’ exam scores:

def record_patient_exam(formdata:Dict[str, Any]) -> bool:
    try:
        pct = round((formdata['score']formdata['total']) * 100, 2)
        status = None
        if (pct >= 70):
            status = 'passed'
        elif (pct < 70) and (pct >= 55):
            status = 'conditional'
        else:
            status = 'failed'
        insert_patient_score(pid=formdata['pid'], qid=formdata['qid'], score=formdata['score'], total=formdata['total'], status=status, percentage=pct)
        return True
    except Exception as e:
        print(e)
    return False

Instead of directly accessing insert_patient_score() to save patient exam scores, record_score() accesses the record_patient_exam() service to compute some formulas before invoking insert_patient_score() from the repository layer for record insertion. The service lessens some friction between the database transactions and the view layer. The following snippet is the view function that accesses the record_patient_exam() service for record exam record insertion:

@app.route('/exam/score', methods=['GET', 'POST'])
def record_score():
    if request.method == 'GET':
        pids = list_pid()
        qids = list_qid()
        return render_template( 'exam/add_patient_score_form.html', pids=pids, qids=qids), 200
    else:
        params = dict()
        params['pid'] = int(request.form['pid'])
        params['qid'] = int(request.form['qid'])
        params['score'] = float(request.form['score'])
        params['total'] = float(request.form['total'])
        result = record_patient_exam(params)
        … … … … … … …
        else:
            return redirect('/exam/task/error')

Aside from calling record_patient_exam(), it also utilizes the list_pid() and list_qid() services to retrieve the IDs. The use of services can help separate the abstraction and use cases from the route functions, which has a beneficial impact on the scope, clean coding, and runtime performance of the routes. Moreover, the project structure can also contribute to clear business flow, maintainability, flexibility, and adaptability.

Create a Note

Modal Close icon
You need to login to use this feature.
notes
bookmark search playlist download font-size

Change the font size

margin-width

Change margin width

day-mode

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Delete Bookmark

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete

Delete Note

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete

Edit Note

Modal Close icon
Write a note (max 255 characters)
Cancel
Update Note

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY