A microservice skeleton
So far in this chapter, we have looked at how Quart works, and at most of the built-in features it provides—all of which we will be using throughout this book. One topic we have not yet covered is how to organize the code in your projects, and how to instantiate your Quart
app. Every example so far has used a single Python module and the app.run()
call to run the service.
Having everything in a module is possible, but will create a lot of headaches unless your code is just a few lines. Since we will want to release and deploy the code, it's better to have it inside a Python package so that we can use standard packaging tools such as pip
and setuptools
.
It is also a good idea to organize views into blueprints, and have one module per blueprint. This lets us keep better track of what each bit of code does, and re-use code whenever possible.
Lastly, the run()
call can be removed from the code since Quart provides a generic run command that looks for an application using information from the QUART_APP
environment variable. Using that runner offers extra options, such as the ability to configure the host and port that will be used to run the app without going into the settings each time.
The microservice project on GitHub was created for this book and is a generic Quart project that you can use to start a microservice. It implements a simple layout, which works well for building microservices. You can install and run, and then modify it. The project can be found at https://github.com/PythonMicroservices/microservice-skeleton.
The microservice
project skeleton contains the following structure:
setup.py
: Distutils' setup file, which is used to install and release the project.Makefile
: A Makefile that contains a few useful targets to make, build, and run the project.settings.yml
: The application default settings in a YAML file.requirements.txt
: The project dependencies following thepip
format produced bypip freeze
.myservices/
: The actual package__init__.py
app.py
: The app module, which contains the app itselfviews/
: A directory containing the views organized in blueprints__init__.py
home.py
: The home blueprint, which serves the root endpoint
-
tests/:
The directory containing all the tests__init__.py
test_home.py
: Tests for the home blueprint views
In the following code, the app.py
file instantiates a Quart
app using a helper function called create_app
to register the blueprints and update the settings:
import os
from myservice.views import blueprints
from quart import Quart
_HERE = os.path.dirname(__file__)
_SETTINGS = os.path.join(_HERE, "settings.ini")
def create_app(name=__name__, blueprints=None, settings=None):
app = Quart(name)
# load configuration
settings = os.environ.get("QUART_SETTINGS", settings)
if settings is not None:
app.config.from_pyfile(settings)
# register blueprints
if blueprints is not None:
for bp in blueprints:
app.register_blueprint(bp)
return app
app = create_app(blueprints=blueprints, settings=_SETTINGS)
The home.py
view uses a blueprint to create a simple route that doesn't return anything:
from quart import Blueprint
home = Blueprint("home", __name__)
@home.route("/")
def index():
"""Home view.
This view will return an empty JSON mapping.
"""
return {}
This example application can run via Quart's built-in command line, using the package name:
$ QUART_APP=myservice quart run
* Serving Quart app 'myservice.app'
* Environment: production
* Please use an ASGI server (e.g. Hypercorn) directly in production
* Debug mode: False
* Running on http://localhost:5000 (CTRL + C to quit)
[2020-12-06 20:17:28,203] Running on http://127.0.0.1:5000 (CTRL + C to quit)
From there, building JSON views for your microservice consists of adding modules to microservices/views, and their corresponding tests.