This video is available to students only

Growing our application with Blueprints

`https://financialmodelingprep.com/api/v3/financials/income-statement/AAPL`

Growing our application with Blueprints

So far, we've been putting all of our server logic into one file, server.py. As our application gets larger, it's going to be harder to continue to do that.

Blueprints allow developers to create modules that define routes and are then imported into the main server. This is helpful if you are designing multiple separate components of a web application. For example an application that has an user facing webpage, an administrative dashboard, and an API could have one blueprint for each of those parts of the website. Each part of that application will often have its own URL routing scheme (/user, /admin, /api) and its own templates and logic. Blueprints are well suited for each of these because they allow routes to share a common routing prefix (for example /api) while also being able to modularize the logic and templates.

Common Misunderstanding: Blueprints may look like separate Flask apps that happen to be imported into the server, but they are not. A better mental model for Blueprints is to think of them as a collection of routes that needs to be "mounted" to an existing Flask application.

In our stock ticker application, we can modularize our application into two "concerns". The home page logic and the financial information for a specific stock ticker.

To create a blueprint within our stock application, we're going to create a folder inside of our application for the blueprints and then eventually import them into our server.py.

mkdir blueprints

Within the blueprints folder, we should create a Python file in which we can create a Blueprint. For the financial one, we'll call it stock.py

At this point, your folder structure should look like this

* blueprints
    * stock.py
* templates (folder)
    * your template files...
* requirements.txt
* server.py
* Procfile

In the last section, our stock ticker quote route looked this

@app.route('/stocks/<string:ticker>')
def view_stock(ticker):
    stock_price = fetch_price(ticker)
    return render_template('stock_quote.html', ticker=ticker, stock_price=stock_price)

We defined the route using the actual Flask application (app) and had to add /quote/ in front of the route. In our stock blueprint, instead of using the application, we will create a Blueprint and use that to define routes.

At the top of stock.py, we're going to define our Blueprint which will involve importing the Blueprint class from Flask, instantiate a Blueprint with a name, and optional arguments to define the url_prefix for all routes in this blueprint.

tip

Maintainability Tip: URL Prefixes are optional, but good practice

Without URL prefixes for blueprints, it can be easy to accidentally define the same route twice and Flask will fail to start once it sees that there is a conflict.

Instead it is generally better practice to have unique url_prefixes for each blueprint you make so you can avoid this problem. In addition, developers looking for the logic for a specific route can quickly find what blueprint it is defined in.

from flask import Blueprint, render_template

stock = Blueprint('stock', __name__, url_prefix='/stocks')

Defining our route will be very similar to how we did earlier, with two changes, the decorator for the route (@app.route) will reference the blueprint instead (@stock.route) and the route path no longer needs /stocks in front of it since the blueprint already sets it as a prefix.

We'll also need to move in the fetch_price function from the server.py.

stock-app/blueprints/stock.py
from flask import Blueprint, render_template
import requests

stock = Blueprint('stock', __name__, url_prefix='/stocks')

def fetch_price(ticker):
    data = requests.get('https://financialmodelingprep.com/api/v3/stock/real-time-price/{}'.format(ticker.upper()),
                        params={'apikey': 'demo'}).json()

At this point, if we run our server, nothing has actually changed. That's because we have not yet imported and registered the stock blueprint we just made. In server.py, we'll start by importing the blueprint we just made.

stock-app/blueprints/server.py
from flask import Flask, render_template

from blueprints.stock import stock

app = Flask(__name__)
app.register_blueprint(stock)

We're specifically importing the blueprint object we've instantiated within sever.py.

We'll also need to update some calls to url_for because we've changed the routing path. What was url_for('view_stock') needs to become url_for('stock.view_stock') to reflect that route is actually in the Blueprint that we initialized with the name stock. In macros.html, update the call to url_for to look like this:

stock-app/templates/macros.html
{% macro stock_quote_link(stock_ticker) %}
    <a href="{{ url_for('stock.view_stock', ticker=stock_ticker) }}">{{ stock_ticker }}</a>
{% endmacro %}

Start a new discussion. All notification go to the author.