Module 6: Creating a backend for your app in Python
Our shopping list app is fully functional, but it depends on a backend server that returns the price of items you add to your shopping list. In this module we’ll create this backend server in Python.
You can find this module’s backend code in the GitLab repository of the course. |
1. Introduction
Many apps communicate with a backend server. It’s called backend because it’s not a user-facing component. This in contrast to the frontend. Your app is the frontend in this case, because the user is interacting with it.
Another way of viewing this is in terms of the client-server model. Your app is the client, and the backend is the server. Your client requests information from the server: the price of an item.
The word 'server' has many meanings: it can be the software handling requests for the client, but the term is also used for the hardware: a computer that runs this server software. |
In practice, a backend for a mobile app usually is running as a HTTP service. The app then accesses this backend using something like the XMLHttpRequest standard introduced in the previous module.
In this module, we’ll create a backend for our app, developed in Python with the Flask framework. You can run this backend on your own computer or on a VPS (virtual private server) on internet.
2. Installing Python
We’re using Python for our backend because it’s a universal, powerful and easy-to-learn programming language. This is not a Python course, so if you want to learn more about Python, have a look at the official Python tutorial or one of the many books about Python programming.
First have a look at the current version of Python on your computer, because maybe it’s already installed. Open a terminal or command prompt on your computer, and run the following command:
python3 --version
If the command returns an error, try:
python --version
If you get a version number starting with 2.7, the Python version is too old. You should have at least Python 3.7, which is supported until 27 June 2023.
If you have a current Python version, you can skip the installation steps and move on to the next section. Otherwise, choose the installation subsection for your operating system.
2.1. Linux
On many Linux distributions, Python is already installed. If not, install it with your distribution’s package manager. For instance, on Ubuntu it goes like this:
sudo apt install python3 python3-pip
Pip is Python’s package manager, and it’s distributed as a separate package on Ubuntu. |
2.2. Windows
On Windows, Python isn’t installed by default, but running python3
brings you to the Microsoft Store, where you can install Python. However, this doesn’t always show you the newest available Python version. So search 'python' in the Microsoft Store and install the latest available version.
2.3. macOS
On macOS, an unsupported Python 2.7 is installed by default. Download the latest available Python 3 version from the page Python Releases for macOS and install it.
3. Creating a backend for your shopping list app with Python and Flask
Flask is an easy-to-use Python framework to create web services. You first have to install it as a pip module:
pip3 install Flask
Let’s build a backend for item prices for your shopping list app, step by step. If you want to delve deeper into Flask, read its Quickstart later.
3.1. Creating a simple web service with Flask
First create the following Python script, e.g. in Visual Studio Code, and name it app.py:
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
Now run the app with the following command in the same directory as where you saved the app:
flask run
This will show you:
* Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
Open the URL that it shows (http://127.0.0.1:5000) in your web browser. This shows you a text Hello, World!.
You can only open this URL on the same computer as the one you’re running Flask on. |
Let’s explain this Python script line by line. In the first line, we import the Flask
class, and the line thereafter we create an object of this class, named app
.
In the next line, the app’s route
decorator tells Flask that it should execute the function on the following line when the URL /
is visited. This function, hello_world()
, returns HTML code for a pagraph of text showing Hello, World!. And this is what you saw in your web browser while visiting the root URL of the web site.
If you view at the source code of the HTML page in your web browser, you’ll see exactly the HTML code returned by the hello_world() function.
|
Quit your Flask app by pressing Ctrl+C.
3.2. Returning JSON data
Now this Flask app returns HTML code, but in our Ubuntu Touch app we want to get the item price data in JSON format. So let’s add a route and a function to return a random price. Your app.py then becomes this:
from random import randrange from flask import Flask, request app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>" @app.route("/itemprice") def itemprice(): return {"name": request.args.get("itemname"), "price": randrange(1000) / 100}
So we create the route /itemprice
, which executes the itemprice()
function. This returns a Python dict, which is automatically converted by Flask to a JSON string.
This JSON object has two name/value pairs. "name"
gets the value of the itemname
URL parameter, which is parsed thanks to the request.args.get
method. You need to add an import of request
from Flask for this to work. And then "price"
gets the value of a random integer between 0 and 1000, divided by 100. So you get a random price between 0 and 10, with two decimals. You need to import randrange
for this to work.
If you now run the Flask app again, visit the URL http://127.0.0.1:5000/itemprice?itemname=apples in your web browser. You’ll see a JSON object with names name
and price
, just like with the public shopping list backend we used in the previous course module.
3.3. Using your Flask app as a backend for your shopping list app
So let’s now use your Flask app as a backend for your shopping list app. First you need to make the Flask app available for all computers on your network (which includes your Ubuntu Touch phone or Docker container running your app). Quit your Flask app if it’s still running, and then run it again with an extra argument on the command line:
flask run --host=0.0.0.0
This tells your operating system to listen on all public IP addresses.
So Flask now also shows you the URL with your computer’s IP address in your local network, in this case 192.168.0.128:
* Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on all addresses (0.0.0.0) WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 * Running on http://192.168.0.128:5000 (Press CTRL+C to quit)
Now the only thing you need to change in your shopping list app to make use of your own backend server is changing the property itemPriceURL
in Main.qml:
property string itemPriceURL: "http://apishoppinglist.codefounders.nl/itemprice.php?itemname="
Change this to:
property string itemPriceURL: "http://192.168.0.128:5000/itemprice?itemname="
Make sure to use the same URL as the one Flask showed you above, adding itemprice?itemname=
to it.
Now run your Ubuntu Touch app:
clickable desktop
If you add an item apples, you’ll see the following line in the console window running Flask:
192.168.0.128 - - [22/Apr/2022 16:34:42] "GET /itemprice?itemname=apples HTTP/1.1" 200 -
This means that your Ubuntu Touch app successfully accessed your own backend. The Flask app returned the price for your item, and this price is shown in your Ubuntu Touch app. So now you have created your own backend for your Ubuntu Touch app!
3.4. Using an SQLite database in your backend
For now your backend just returns a random price for every item. But that’s not really useful. Shouldn’t we store some kind of price list in the backend? Yes, and you’ve already learned how to store data in the previous course module: with a database.
Luckily Python also has an SQLite module, sqlite3, so you can reuse your knowledge about SQLite from the previous course module. So we can extend our Flask app to read the prices of items from an SQLite3 database and return them when requested.
In a real production-ready backend you should also add a web page to your Flask app to add items with their prices to the database, but then you need to add authentication, authorization, and so on, and that’s not the scope of this course. So we’ll just start the sqlite3
command on the command line, create a table in the database and add some rows to it. We can then read this database file in our Flask app.
So first open a new database file with the sqlite3
command. Do this in the same directory as your app.py file:
sqlite3 itemprices.sqlite
Now create a table with name
and price
columns:
CREATE TABLE IF NOT EXISTS Pricelist (name TEXT, price REAL);
This creates a table with name Pricelist
where each record has a name
column of type TEXT
and a price
column of type REAL
. A real number is a floating-point value, such as 1.35 or 9.13.
Now that you have this table in your SQLite database, add some items with their prices with the following SQL statements:
INSERT INTO Pricelist (name, price) VALUES ("apples", 1.35); INSERT INTO Pricelist (name, price) VALUES ("bananas", 2.48); INSERT INTO Pricelist (name, price) VALUES ("water", 9.13); INSERT INTO Pricelist (name, price) VALUES ("bread", 2.51);
Feel free to add other items.
After this, quit the SQLite command line with Ctrl+D or the .quit
command. This automatically saves your database in the file itemprices.sqlite
.
Now how do we access this database in our Flask app? This is done using the sqlite3
module which is built-in in Python. The code of our app then becomes this:
from random import randrange from sqlite3 import connect from flask import Flask, g, request app = Flask(__name__) DATABASE = "itemprices.sqlite" def get_db(): db = getattr(g, "_database", None) if db is None: db = g._database = connect(DATABASE) return db @app.teardown_appcontext def close_connection(exception): db = getattr(g, "_database", None) if db is not None: db.close() def query_db(query, args=(), one=False): cur = get_db().execute(query, args) rv = cur.fetchall() cur.close() return (rv[0] if rv else None) if one else rv @app.route("/") def hello_world(): return "<p>Hello, World!</p>" @app.route("/itemprice") def itemprice(): itemname = request.args.get("itemname") try: price = query_db( "SELECT price from Pricelist where name = ?", [itemname], one=True )[0] except TypeError: price = 0 return {"name": itemname, "price": price}
This is a lot of extra code, but most of it are just some helper functions. So we import the connect
function from the sqlite3
module, define the location of our database file in the DATABASE
variable, and then set up some helper functions. If you want to know more about these, read the page Using SQLite 3 with Flask in Flask’s documentation. In short:
-
get_db()
connects to the database. -
close_connection()
closes the database when the Flask app quits. -
query_db
queries the database and returns the results.
Now in our itemprice()
function, we get the item name for which the user requests the price out of the URL parameters and store it in the itemname
variable. Then we query the database for the price
column in the Pricelist
table where the name
column is equal to the itemname
variable, and we only return one result. Because the result is a tuple, we get the first element of it with [0]
.
Now when the requested item name isn’t in the database, the query_db()
function returns None
, and this can’t be indexed with [0]
, so this throws a TypeError
exception. In this case we catch this exception and just set the price to 0.
Ultimately, we return the dictionary with the item’s name and price.
Now run your Flask app and run your Ubuntu Touch app again. If you add items to your shopping list that are in the database, they’ll get the corresponding price in the database. If you add items that aren’t listed in the database, they are added with ther price set to 0.
4. Running your backend on a public server
You have now implemented a backend for your Ubuntu Touch app, but it only works for yourself in your local network. If you want to support your users with this backend, it has to run on a publicly available server on internet. It would lead us too far to explain all the details, because you can do this in many different ways and you would have to add many features to make this a production-ready backend. But we’ll explain the general approach.
4.1. Deploying your Flask app to a WSGI server
Flask’s built-in web server is not suitable for production. Every time you run your Flask app, it reminds you about this with a warning. For a production-ready setup, you need to deploy it to a WSGI server. WSGI stands for Python’s Web Server Gateway Interface, which is a standard interface between web servers and Python web applications.
There are two ways to deploy your Flask app to a WSGI server: hosted and self-hosted.
4.1.1. Hosted options
If you don’t want to administer your own server, there are many cloud platforms you can deploy Flask on, such as Heroku, Google App Engine, AWS Elastic Beanstalk, and Microsoft Azure App Service. You can finds tutorials for these and other options in Flask’s documentation.
4.1.2. Self-hosting on a VPS
The other option is self-hosting: you rent a virtual private server (VPS) and install a WSGI server and your Flask app on it.
A VPS is a virtual machine running a complete Linux server distribution, such as Debian GNU/Linux or Ubuntu Server, and available on internet. You configure it with a certain amount of RAM and disk storage. After the VPS provider has set up the virtual machine for you, you need to administer the Linux distribution and you can install and configure your own software. You pay for your use of the virtual machine month by month.
The Flask documentation refers to a couple of self-hosted options. For instance, you can use the mod_wsgi module for the Apache web server, or uwsgi with the nginx web server.
4.2. Using a domain name for your backend server
Whatever deployment option you choose (hosted on a cloud platform or self-hosted on a VPS), the result is the same: your Flask app is accessible on a public IP address. But it’s better to make your server available using a domain. This means you can always change your backend to another platform or another server, with another IP address, as long as you let the domain refer to the new IP address.
So first choose a domain name, such as example.com. This shouldn’t be as memorable as for a web site, as you’re probably only using the domain name in your Ubuntu Touch app’s source code. Then buy this domain name from a domain registrar. You’ll need to renew this every year.
You can reuse a domain name you’ve already bought, and use a subdomain of this domain for your backend server. |
Each domain registrar has its own way of linking your domain or a subdomain (such as backend.example.com) to an IP address. Consult your registrar’s documentation. In technical terms, what you’re setting is the domain’s A record (for IPv4 addresses) and/or the domain’s AAAA record (for IPv6 addresses).
So if you link backend.example.com in your domain registrar’s web interface to the IP address of your VPS or cloud instance, you can change the property string itemPriceURL
in your Ubuntu Touch app’s source code to "http://backend.example.com/itemprice?itemname=" to use the Flask app you’ve deployed on internet.
4.3. Using a TLS certificate for secure communication
There’s a last component you need for secure communication between your Ubuntu Touch app and its backend: a TLS certificate for your domain. With a TLS certificate, the HTTP requests from your Ubuntu Touch app to your backend and the responses are encrypted. Moreover, your app can be sure that it’s talking to your backend (or at least: something on its domain) and not to another server.
The easiest way to get a TLS certificate for your own domain is with Let’s Encrypt. If you’ve deployed your Flask app on your own VPS, you can install an ACME client that automatically requests a new certificate when needed and installs it in your distribution. One of these ACME clients is Certbot, which has documentation about setting it up for many combinations of Linux distributions and web servers. If you’re using a hosted solution, consult its documentation about certificate management.
As soon as you have a TLS certificate for your domain and set it up on your server, you can change the property string itemPriceURL
in your Ubuntu Touch app’s source code to "https://backend.example.com/itemprice?itemname=" to access your Flask app over HTTPS, which is HTTP over an encrypted TLS connection. Your backend is now ready.