In my previous post, Creating an API with python: Part 10: Integration Tests, I added integration tests, which replaced the test.sh
script with python unit tests that test the API functionality. In this post, I will set up the FastAPI API to run as a service, controllable via the systemctl
command.
Prerequisites
These prerequisites are assumed for this post, although this post can be used as a guide to setting up any FastAPI python API as a service, even without these specific prerequisites:
- Creating an API with python: Part 1: GET Endpoints
- Creating an API with python: Part 2: MariaDB Database
- Creating an API with python: Part 3: POST Endpoints
- Creating an API with python: Part 4: DELETE Endpoints
- Creating an API with python: Part 5: Authentication
- Creating an API with python: Part 6: HTTPS and Proxying
- Creating an API with python: Part 7: CORS
- Creating an API with python: Part 8: Multiple Account Support
- Creating an API with python: Part 9: Authentication Scopes
- Creating an API with python: Part 10: Integration Tests
As a reminder, the code for the FastAPI API is now on GitHub, with the project name taglink-api
. You can checkout the latest copy of the code here: https://github.com/liz-allthecoding/taglink-api.
Step 1: Create a Service User
First up, we will create a service user, which will be the user under which the service will be running.
- On your server, run the following to create a new group called
taglink
:$ sudo su $ groupadd -r taglink
-
Now create the
taglink
user and assign it to the grouptaglink
:$ useradd -r -g taglink -d /home/taglink -s /sbin/nologin -c "Taglink service account" taglink
Step 2: Deploy the Code
The code should currently be residing over the shared directory on your server. Create a new directory on your server, which will be the installation location for the code. Then copy the code across to this directory.
- On your server, run the following (replacing
/home/osboxes/vboxshare/taglink-api/
with the path to your code, if located elsewhere):$ sudo su $ mkdir -p /opt/taglink-api $ cp -r /home/osboxes/vboxshare/taglink-api/* taglink-api/ $ cd /opt/ $ chown -R taglink:taglink taglink-api
-
Now create the
venv-fastapi
venv and install the required python packages to it:$ sudo su $ cd /opt/taglink-api $ python -m venv .venv-fastapi $ . .venv-fastapi/bin/activate (.venv-fastapi) $ pip install --upgrade pip (.venv-fastapi) $ pip install "fastapi[all]" (.venv-fastapi) $ pip install sqlalchemy (.venv-fastapi) $ pip install mariadb (.venv-fastapi) $ pip install python-multipart (.venv-fastapi) $ pip install "python-jose[cryptography]" (.venv-fastapi) $ pip install "passlib[bcrypt]"
-
Change the ownership of the
venv-fastapi
venv to thetaglink
user:$ chown -R taglink:taglink .venv-fastapi
Step 3: Add start.sh
The start.sh
file should be in the top directory of /opt/taglink-api
if you copied your code from a recent clone of the github repo. If not, create the file:
- Create a file called
start.sh
in the/opt/taglink-api
directory, and populate it with these contents:#!/bin/bash . /opt/taglink-api/.venv-fastapi/bin/activate uvicorn --host 0.0.0.0 main:app --root-path /api --reload
-
Add executable permissions:
$ chmod ug+x start.sh
Step 4: Create the Systemd Service Configuration File
Create the systemd service configuration file:
-
Change directory to where the systemd service configuration is located:
$ sudo su $ cd /etc/systemd/system
- Create a file called
taglink-api.service
in the/etc/systemd/system
directory, and populate it with these contents:[Unit] Description=TagLink API Service After=network.target ConditionPathExists=/opt/taglink-api/.venv-fastapi [Service] Type=simple SyslogIdentifier=taglink-api WorkingDirectory=/opt/taglink-api Environment="PYTHONPATH=/opt/taglink-api" Environment="SYSLOG_IDENT=taglink-api" ExecStart=/opt/taglink-api/start.sh User=taglink Group=taglink Restart=always RestartSec=20 [Install] WantedBy=multi-user.target
Step 5: Start the Service
Start the service using the systemctl command.
-
$ sudo systemctl start taglink-api
-
Check if the service is running with this command:
$ sudo systemctl status taglink-api
-
If all is well, you should get an output something like this:
[osboxes@osboxes fastapi]$ sudo systemctl status taglink-api ● taglink-api.service - TagLink API Service Loaded: loaded (/etc/systemd/system/taglink-api.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2022-11-18 18:39:09 GMT; 1s ago Main PID: 1474 (start.sh) Tasks: 4 CGroup: /system.slice/taglink-api.service ├─1474 /bin/bash /opt/taglink-api/start.sh ├─1476 /opt/taglink-api/.venv-fastapi/bin/python3.6 /opt/taglink-api/.venv-fastapi/bin/uvicorn --host 0.0.0.0 main:app --root-path /api --reload ├─1479 /opt/taglink-api/.venv-fastapi/bin/python3.6 -c from multiprocessing.semaphore_tracker import main;main(4) └─1480 /opt/taglink-api/.venv-fastapi/bin/python3.6 -c from multiprocessing.spawn import spawn_main; spawn_main(tracker_fd=5, pipe_handle=7) --multiprocessing-fork Nov 18 18:39:09 osboxes.org systemd[1]: Started TagLink API Service. Nov 18 18:39:09 osboxes.org taglink-api[1474]: INFO: Will watch for changes in these directories: ['/opt/taglink-api'] Nov 18 18:39:09 osboxes.org taglink-api[1474]: INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) Nov 18 18:39:09 osboxes.org taglink-api[1474]: INFO: Started reloader process [1476] using watchgod Nov 18 18:39:10 osboxes.org taglink-api[1474]: /opt/taglink-api/.venv-fastapi/lib64/python3.6/site-packages/jose/backends/cryptography_backend.py:4: CryptographyDeprecationWarning: Python 3.6 is no longer supported by ... future release. Nov 18 18:39:10 osboxes.org taglink-api[1474]: from cryptography.exceptions import InvalidSignature, InvalidTag Nov 18 18:39:10 osboxes.org taglink-api[1474]: INFO: Started server process [1480] Nov 18 18:39:10 osboxes.org taglink-api[1474]: INFO: Waiting for application startup. Nov 18 18:39:10 osboxes.org taglink-api[1474]: INFO: Application startup complete. Hint: Some lines were ellipsized, use -l to show in full.
-
If there are issues, or you want to see the logs, you can run:
$ sudo journalctl -f -n1000 -u taglink-api
-
If you want to stop the service, run:
$ sudo systemctl stop taglink-api
-
If you want to enable the service to run at system boot, run:
$ sudo systemctl enable taglink-api
Step 6: Run the Integration Tests
Run the integration tests to verify that the API is working correctly.
-
Ensure that the service is running:
$ sudo systemctl start taglink-api
- On your server, change to the code directory (
~/vboxshare/fastapi
should be replaced with the path to your FastAPI python code):$ cd ~/vboxshare/fastapi
-
Run the integration tests:
$ ./integration_test.sh
Conclusion
You should now have a FastAPI API running as a service, meaning it can be controlled with systemctl
, can be configured to start at system boot, and is resilient to crashes (the systemd configuration is set to restart the service 20 seconds after a crash).
If you want to find out about enabling utf-8 character support and preventing database connections from dropping, see my follow-on post, Creating an API with python: Part 12: Database Character Encoding and Connections.
Thanks for reading!
Recent Comments