Flask Boilerplate - Structuring Flask App
Tags: showdev, python, webdev, opensource
Published: 2020-08-06 12:04:17

---
title: Flask Boilerplate - Structuring Flask App
published: true
description: Introducing Flask Boilerplate to quickly get started with production-grade flask application. It has some additional packages pre-configured for ease of development.
tags: showdev, python, webdev, opensource 
---

Flask is a lightweight [WSGI](https://wsgi.readthedocs.io/) web application framework. It is part of the categories of the micro-framework with little to no dependencies on external libraries. It doesn't enforce any dependencies or project layout. Because of which you will find plenty of different project layouts out there. 

While I started working on Flask, I got confused to choose the correct layout for my applications. In this post, we will discuss some of the important points to keep in mind while structuring a Flask application with the help of my `Flask Boilerplate` project. 
{% github idris-rampurawala/flask-boilerplate no-readme %}

**:memo: NOTE**
- This boilerplate was created based on my cumulative knowledge gained by writing multiple flask projects
- This may not be the choice of layout for your app as you may have different requirements but a great way to kick start a Flask app and add packages as per the need
- It is lightweight in that it only has minimal packages to achieve the necessities of an app. But you can surely customize it based on your need :wink:

### Why Boilerplate? :thinking:
When I started working on a flask application for the first time, I had a tough time figuring out the correct structure and packages to achieve the necessities of my flask app. Hence, I decided to make this very basic lightweight boilerplate available for the community while I figured out the structure working on multiple live projects in the past.

When we start a project from scratch, especially the backend services, there are some basic functionalities that it should possess. The following are some of the points in building up an efficient app explained concerning this flask boilerplate.

<table>
 <tr>
  <th>Shortcuts
  </th>
 </tr>
 <tr>
  <td>
   <a href="#folder-structure">Folder Structure</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#managing-external-packages">Managing External Packages</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#workspace-setup">Workspace Setup</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#configuration">Configuration</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#logging">Logging</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#authentication">Authentication</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#db-setup">Database Setup</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#celery-setup">Task Queues (Celery) Setup</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#deployment">Deployment</a>
  </td>
 </tr>
 <tr>
  <td>
   <a href="#api-caching-validation">API Caching and Validation</a>
  </td>
 </tr>
</table>

#### 1. Folder Structure <a name="folder-structure"></a>
Flask applications generally have many variations in their folder structure. The choice of keeping files in different folders is dependent on an individual/team/project type. On a high level, flask application can be created even with a single page or via a factory pattern method. Let's talk a bit more about the concepts here:

- *Factory Pattern*
Well-structured web apps separate logic between files and modules, typically with separation of concerns in mind. This seems tricky with Flask at first glance because our app depends on an `app object` that we create via `app = Flask(__name__)`. Separating logic between modules means we would be importing this app object all over the place, eventually leading to problems like circular imports. The `Flask Application Factory` refers to a common `pattern` for solving this dilemma. The reason why the `Application Factory` is so important has to do with something called `Flask's Application Context`. Hence, we are making use of factory pattern inside this boilerplate project to make our lives a bit easier.

- *Blueprints*
In a normal project, the number of views, and templates, and models, and forms, etc. will grow. You can (hackily) separate them, but wouldn’t it be nice to have something that groups related views, templates, models, and forms? [Blueprints](https://flask.palletsprojects.com/en/1.1.x/tutorial/views/)! They are a great way to modularly compose Flask applications, which will help scale up projects.

Well, in this boilerplate, there's one blueprint `core` serving as a base and more can be added later as shown below:
```py
# app/__init__.py
def create_app():
    ...
    app = Flask(APP_NAME)
    ...
    from .core.views import core as core_blueprint
    app.register_blueprint(
        core_blueprint,
        url_prefix='/api/v1/core'
    )
```
So, the folder structure looks as :point_down:
```sh
├── app
│   ├── core                # blueprint
│   │   ├── __init__.py
│   │   ├── constants.py
│   │   ├── enums.py
│   │   ├── tasks.py        # celery tasks specific to this blueprint
│   │   └── views.py
│   ├── config.py
│   └── __init__.py         # app initialization logic
├── .env
├── .gitignore
├── Pipfile
├── Pipfile.lock
├── README.md
├── authentication.py
├── celery_worker.py
└── run.py
```

#### 2. Managing External Packages <a name="managing-external-packages"></a>
One of the most important steps is to create a virtual environment for python projects to manage dependencies. There are various python packages for this purpose such as `virtualenv`, `pyenv`, etc. This boilerplate uses [pipenv](https://pypi.org/project/pipenv/) to address all the [issues](https://realpython.com/pipenv-guide/#problems-that-pipenv-solves) that I have faced using other packages for managing dependencies. `Pipenv` automatically creates and manages a virtual environment for your projects, as well as adds or removes packages from your `Pipfile` as you install/uninstall packages.

This boilerplate has those packages which are required to build up an app and hence you can always customize based on your need :wink:

#### 3. Workspace Setup <a name="workspace-setup"></a>
Though not directly related to an app, your workspace setup does affect your app creation process. Hence, setting up a workspace is a major step to speed up your working environment. I have written a post that specifically talks about setting up a python workspace in a visual studio code editor which you can refer and quickly get started :v:
{% post idrisrampurawala/setting-up-python-workspace-in-visual-studio-code-vscode-149p %}


#### 4. Configuration <a name="configuration"></a>
Configuring a Flask app (or maybe any app) generally requires a lot of effort (if we are not experienced). In general, there can be 2 aspects to it -

- *Storing secrets securely*
Usually, a lot of secrets makes up a project such as DB credentials, API keys, etc. It is recommended to keep these secrets in a secured location not being tracked in `git`. Which is why we have a `.env` (git untracked, to be created from `.env.example`) file at the root location of this boilerplate which makes all the secrets present in it available in our project using [python-dotenv](https://pypi.org/project/python-dotenv/) package. Hence, it is super easy to get started with just creating `.env` from `.env.example` by setting correct values :grin:

- *Creating multiple configurations (dev, staging, prod)*
Another important point is to separate global configurations based on the environment such as dev, staging, prod. That's the reason we have `config.py`, a file containing configuration classes based on the environments that get loaded in the Flask app based on the current working environment (which can be set in `.env`).
```py
# configuration classes (app/config.py)
class BaseConfig(object):
    ''' Base config class. '''
...

class Development(BaseConfig):
    ''' Development config. '''
...

class Staging(BaseConfig):
    ''' Staging config. '''
...

class Production(BaseConfig):
    ''' Production config '''
...
config = {
    'development': Development,
    'staging': Staging,
    'production': Production,
}
```
```py
# app/__init__.py
from config import config
...

def create_app():
    # loading env vars from .env file
    load_dotenv()
    APPLICATION_ENV = get_environment()
    app = Flask(APP_NAME)
    # loading config based on current environment
    app.config.from_object(config[APPLICATION_ENV])
    # APPLICATION_ENV is set in .env to set current environment

```

#### 5. Logging <a name="logging"></a>
Logging is a means of tracking events that happen when some software runs. We add logging calls to our code to indicate that certain events have occurred.

As we already have environment based configurations in our app, all the other configurations can be changed according to the current app environment (dev, staging, prod). The loggers are configured in `config.py` and can be overridden in the respective app environments (dev, staging, prod) as shown below :point_down:
```py
# config.py
class BaseConfig(object):
    ''' Base config class. '''
    ...
    LOG_INFO_FILE = path.join(basedir, 'log', 'info.log')
    LOG_CELERY_FILE = path.join(basedir, 'log', 'celery.log')
    LOGGING = {
        'version': 1,
    ...
```

#### 6. Authentication <a name="authentication"></a>
Authentication can be added authentication as per the need of the application. To start with, this boilerplate has `API-Key` based authentication whereas the `API-Key` is declared in `.env` file. In file, `authentication.py`, a decorator looks for `x-api-key` header in the request and returns `401` in case of mismatch. Once you have set up the app, you can test the test route (`/core/restricted`) for the same via curl with your API key set in `.env`.
```sh
$ curl --location --request GET 'http://localhost:5000/api/v1/core/restricted' --header 'x-api-key: <your-api-key>'
```

> For more complex authentication logic, please write a custom middleware.

#### 7. Database Setup <a name="db-setup"></a>
To keep the boilerplate as light as possible of the packages, it does not have any database package added. But worry not if you want to add one. :relieved: It is pretty easy to configure the database as this boilerplate is created via the factory pattern method along with environment-based configuration as discussed in the above points. Let's take an example of one of the popular library - [SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/).
```py
# app/__init__.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app(config_filename):
    ...
    app = Flask(__name__)
    app.config.from_object(config[APPLICATION_ENV])
    ...
    db.init_app(app)
```
The configuration would be read directly from `app.config` which we have loaded from `config.py`.

#### 8. Task Queues (Celery) Setup <a name="celery-setup"></a>
Task queues are used as a mechanism to distribute work across threads or machines. Commonly, even a small microservice would require to run tasks in the background (async). Hence, this boilerplate comes with a pre-loaded popular task queue [Celery](https://docs.celeryproject.org/en/stable/getting-started/introduction.html).

The configuration is quite simple as we are using Flask's factory pattern. We have also added a separate customized logger for celery logs which writes to a separate configurable file `celery.log`. Running celery is as easy as just running a command `celery worker -A celery_worker.celery -l=info` (from the root of our project).

#### 9. Deployment <a name="deployment"></a>
[Flask Documentation](https://flask.palletsprojects.com/en/1.1.x/deploying/) provides a very good list of deployment options and the necessary steps as well. Also, you can refer to my earlier post on `Deploying the Django application` which is similar for flask application as well (with some minute changes). :smile:

{% post idrisrampurawala/deploying-django-with-celery-and-redis-on-ubuntu-3fo6 %}

#### 10. API Caching and Validation <a name="api-caching-validation"></a>
We already covered a lot of points but two main aspects of having a robust microservice are to have an efficient validation and caching capability. This boilerplate comes with following two packages to achieve the same:
<table>
<tr>
<td><a href="https://redislabs.com/lp/python-redis/" target="_blank">Redis</a></td>
<td> A Python Redis client for caching</td>
</tr>
<tr>
<td><a href="https://webargs.readthedocs.io/" target="_blank">Webargs</a></td>
<td> A Python library for parsing and validating HTTP request objects</td>
</tr>
</table>
---

### :nerd_face: Getting started with flask boilerplate
So far we talked about most of the points an ideal project requires that comes pre-loaded with this boilerplate. Whatever may be your use case for creating an app such as `an email service`, `a communication service`, `reporting service`, or even `a microservice`, you can use this boilerplate with minimal customization.

You can start using [flask boilerplate](https://github.com/idris-rampurawala/flask-boilerplate) using the following installation steps and kick start your project!
```sh
# clone the repo
$ git clone https://github.com/idris-rampurawala/flask-boilerplate.git
# move to the project folder
$ cd flask-boilerplate
# create pipenv environment for python 3
$ pipenv --three
# activate the pipenv environment
$ pipenv shell
# install all dependencies (include -d for installing dev dependencies)
$ pipenv install -d
# create `.env` from `.env.example` and set appropriate environment variables
# run the project
$ python run.py
# optionally check if everything is working correctly by calling status apps (check Test section of readme)
```
All set! Flask boilerplate is up and running and waiting for you to write some cool stuff from it :partying_face:

---

### :star: Useful Links

-  [Flask Boilerplate](https://github.com/idris-rampurawala/flask-boilerplate)
- [Flask Documentation](https://flask.palletsprojects.com/)
- [Pipenv Guide](https://realpython.com/pipenv-guide/)
- [Celery](https://docs.celeryproject.org/en/stable/getting-started/introduction.html)
- [Python Redis](https://redislabs.com/lp/python-redis/)
- [Webargs](https://webargs.readthedocs.io/)

---

If you find this helpful or have any suggestions, feel free to comment. Also, do not forget to hit :heart: or :unicorn: if you like my post.

See ya! until my next post :yum: