This repository contains the backend API for the Swedeb project. It is a Python application built with the FastAPI framework, designed to serve data to the frontend and handle complex queries.
The backend is built on a containerized architecture, leveraging modern Python tooling and best practices.
- Python 3.12: The core programming language.
- The IMS Open Corpus Workbench: Tools for managing and querying large text corpora.
- FastAPI: A high-performance web framework for building APIs.
- Docker: For containerizing the application, ensuring a consistent environment. The final image is built on a custom base image that includes CWB (Corpus Workbench) functionality.
- GitHub Container Registry (GHCR): For hosting the final Docker application image.
- Swedeb Frontend: The frontend application for the Swedeb project, built with Vue3 and Quasar.
- Swedeb Sample Data: Produces data for the Swedeb infrastructure based on SWERIK data.
- humlab-penelope: A tools package supporting text analysis using Python.
- pyriksprot: A Python package for reading and processing SWERIK parliamentary data.
- pyriksprot-tagger: A tool for annotating and tagging SWERIK parliamentary data.
- cwb-ccc: A Python package for working with the CWB (Corpus Workbench) command-line tools.
- stanza: A Python NLP library for tokenization, lemmatization, and part-of-speech tagging.
- pydantic: For data validation and settings management using Python type annotations.
- uvicorn: An ASGI server for running FastAPI applications.
- Poetry: For dependency management and packaging.
- pytest: For running tests.
- black: A code formatter to ensure consistent code style.
- isort: For sorting imports in Python files.
This project employs a fully automated release pipeline using GitHub Actions and semantic-release. This system handles versioning, building artifacts, and publishing releases without manual intervention, ensuring consistency and reliability.
The entire release process is triggered automatically whenever a commit is pushed to the main branch.
-
Commit Convention is Key: The process relies entirely on the Conventional Commits specification. The format of each commit message (e.g.,
feat:,fix:,docs:) dictates how the project is versioned. -
Workflow Trigger: A push to
mainstarts theRelease Backendworkflow. -
Version Calculation:
semantic-releaseanalyzes all commits since the last release tag. It automatically determines the next version number based on the commit types:fix:-> Patch release (e.g.,1.2.0->1.2.1)feat:-> Minor release (e.g.,1.2.0->1.3.0)BREAKING CHANGE:-> Major release (e.g.,1.2.0->2.0.0)
-
Prepare Assets:
- The workflow calls a script that bumps the version number in
pyproject.toml(viapoetry version) and synchronizes it with the__version__variable inapi_swedeb/__init__.py. - It then builds the Python package into a wheel (
.whl) file inside thedist/directory.
- The workflow calls a script that bumps the version number in
-
Create GitHub Release:
- A new GitHub Release is created with the new version tag (e.g.,
v1.3.0). - A changelog is automatically generated from the commit messages and added to the release notes.
- The built Python wheel (
.whl) is uploaded as an artifact to this release.
- A new GitHub Release is created with the new version tag (e.g.,
-
Build & Publish Docker Image:
- The workflow builds a new Docker image for the application. This image uses the specified frontend version and installs the Python backend from the newly created wheel.
- The final image is tagged (e.g., as
v1.3.0,v1.3,v1, andlatest) and pushed to the GitHub Container Registry (GHCR).
-
Finalize Commit:
- To complete the cycle,
semantic-releasecommits the updatedpyproject.tomlandCHANGELOG.mdfiles back to themainbranch and pushes the new version tag. This commit is marked with[skip ci]to prevent the workflow from re-triggering itself.
- To complete the cycle,
As a developer, your only responsibility is to write clear, conventional commit messages. The automation handles the rest.
-
Create a feature branch:
git checkout -b my-new-api-endpoint
-
Make your changes.
-
Commit your work using the Conventional Commits specification. This is the crucial step.
-
For a new feature (triggers a minor release):
git commit -m "feat: add endpoint for user authentication" -
For a bug fix (triggers a patch release):
git commit -m "fix: resolve data race condition in corpus query" -
For changes that should not trigger a release (e.g., docs, tests, refactoring):
git commit -m "docs: update API documentation for auth endpoint" git commit -m "refactor: improve performance of database queries"
-
For a breaking change (triggers a major release):
git commit -m "feat: switch from XML to JSON for API responses BREAKING CHANGE: The default API response format is now JSON. Clients expecting XML must update their headers to 'Accept: application/xml'."
-
-
Push your branch and open a Pull Request to
main. -
Once your PR is reviewed and merged into
main, the release pipeline will automatically run.
-
Clone the repository:
git clone <repository_url> cd <repository_directory>
-
Install Poetry: Follow the official installation instructions to install Poetry.
-
Install Dependencies: This command creates a virtual environment and installs all dependencies from
pyproject.tomlandpoetry.lock.poetry install
-
Run the Development Server: Use
poetry runto execute commands within the project's virtual environment.# Replace 'api_swedeb.main:app' with the correct path to your FastAPI app instance poetry run uvicorn api_swedeb.main:app --reloadThe API will be available at
http://127.0.0.1:8000.
Developers do not need to create any special tokens for the normal contribution process.
However, if you need to test changes to the CI/CD workflow itself, you can use act to run the workflow locally. This requires a GitHub Personal Access Token (PAT) to allow act to interact with the GitHub API.
-
Install
act: Follow the official installation instructions. -
Create a Personal Access Token (PAT):
- Go to your GitHub Settings -> Developer settings -> Personal access tokens -> Tokens (classic).
- Generate a new token with the following scopes:
repo,workflow, andwrite:packages. - Copy the generated token (
ghp_...) and save it securely, for example in a file at~/.ghcr_token.
-
Run the Release Workflow Locally: Use the
-jflag for the job ID and-sto provide your PAT as a secret.# This command simulates the release job in "dry-run" mode act -j release -s GITHUB_TOKEN="$(cat ~/.ghcr_token)"
actwill show you whatsemantic-releasewould do without actually publishing anything, which is perfect for testing.
This project uses several environment variables to configure the build and runtime behavior of the application. These variables can be set in your local environment or in your CI/CD pipeline.
| Variable Name | Description | Phase |
|---|---|---|
SWEDEB_BACKEND_SOURCE |
The source of the backend (workdir or pypi) | Build Only |
NODE_VERSION |
The Node.js version to use for building the frontend | Build Only |
SWEDEB_ENVIRONMENT |
The current environment (development, staging, production) | Build & Runtime |
SWEDEB_BACKEND_TAG |
The backend version to deploy (branch, tag, commit, or 'workdir') | Build & Runtime |
SWEDEB_FRONTEND_TAG |
The frontend version to deploy (branch, tag, commit) | Build & Runtime |
SWEDEB_IMAGE_NAME |
The base image name | Build & Runtime |
SWEDEB_CONTAINER_NAME |
The running container name (SWEDEB_ENVIRONMENT will be appended) | Build & Runtime |
SWEDEB_IMAGE_TAG |
The target Docker image tag (staging or latest) | Build & Runtime |
SWEDEB_PORT |
The port to expose the container on | Build & Runtime |
SWEDEB_HOST_PORT |
The host port to expose the container on | Build & Runtime |
SWEDEB_SUBNET |
The subnet to use for the container | Build & Runtime |
SWEDEB_DATA_FOLDER |
The data folder to mount into the container | Build & Runtime |
SWEDEB_CONFIG_PATH |
The config file to mount into the container | Build & Runtime |
METADATA_VERSION |
The version of the metadata to use | Runtime Only |
CORPUS_VERSION |
The version of the corpus to use | Runtime Only |
SWEDEB_METADATA_FILENAME |
The path to the metadata file to mount into the container | Runtime Only |
This project utilizes Docker and Docker Compose to manage different environments: Development, Staging, and Production. This document outlines the setup and deployment process for each.
- Consistency: The Docker build process aims to be as consistent as possible across all environments.
- Configuration via Environment Variables: Application behavior, connection strings, image tags, and network names are primarily controlled by environment variables, managed through
.envfiles specific to each environment. - Single
docker-compose.yml: We use a singledocker-compose.ymlfile that is parameterized by environment variables.
Environment-specific configurations are managed using .env files. You will need to create these based on the provided examples. These files are typically gitignored to prevent committing sensitive or environment-specific data.
.env.development: For local development..env.staging: For the staging environment..env.production: For the production environment.
Example structure of an environment file (e.g., .env.development):
# Environment identifier
SWEDEB_ENVIRONMENT=development
# Docker Image Configuration
SWEDEB_IMAGE_NAME=your-repo/swedeb-api # Or just swedeb-api if building locally
SWEDEB_IMAGE_TAG=dev-latest
SWEDEB_BACKEND_TAG=dev-latest # Build arg for Dockerfile
SWEDEB_FRONTEND_TAG=dev # Build arg for Dockerfile
# NODE_VERSION=20 # Build arg for Dockerfile, if needed
# Docker Compose Runtime Configuration
SWEDEB_CONTAINER_NAME=swedeb_api
SWEDEB_HOST_PORT=8094 # Port on the host machine
SWEDEB_PORT=8092 # Port the application listens on inside the container
SWEDEB_NETWORK_NAME=swedeb_development_network # Actual Docker network name
# Application Specific Configuration
SWEDEB_CONFIG_PATH=config/config_development.yml
SWEDEB_DATA_FOLDER=./data_dev # Local path for development data
SWEDEB_METADATA_FILENAME=./metadata/dev_metadata.db # Example
METADATA_VERSION=dev # Example
# ... other application-specific variables(Ensure you have corresponding .env.staging and .env.production files with appropriate values.)
Our docker-compose.yml is designed to read variables from an environment-specific .env file determined by the SWEDEB_ENVIRONMENT variable.
Key parts of docker-compose.yml:
# docker-compose.yml (snippet)
version: '3.8'
services:
swedeb_api:
build:
context: .
args: # Populated from the loaded .env.<environment> file
SWEDEB_PORT: "${SWEDEB_PORT}"
SWEDEB_BACKEND_TAG: "${SWEDEB_BACKEND_TAG}"
# ... other build args
image: "${SWEDEB_IMAGE_NAME}:${SWEDEB_IMAGE_TAG}"
container_name: "${SWEDEB_CONTAINER_NAME}-${SWEDEB_ENVIRONMENT}"
env_file:
- ".env.${SWEDEB_ENVIRONMENT}" # Loads the specific .env file
# ... other service configurations
networks:
- swedeb_app_network
networks:
swedeb_app_network:
name: "${SWEDEB_NETWORK_NAME}" # Actual network name from .env.<environment>
driver: bridgeTypically run on a developer's local machine.
- Prerequisites:
- Git, Docker, and Docker Compose installed.
- Repository cloned.
- Setup:
- Create or copy the
.env.developmentfile in the project root. - Populate it with your local development settings (e.g., local paths for
SWEDEB_DATA_FOLDER).
- Create or copy the
- Running:
Alternatively, use a Makefile target:
# Set the environment context export SWEDEB_ENVIRONMENT=development # Build (if needed) and start services docker-compose up --build -d # To stop docker-compose down
make up-dev
Deployed to a dedicated staging server for testing and validation before production.
- Trigger:
- Deployment to staging is typically initiated manually via a GitHub Actions
workflow_dispatchtrigger or automatically on pushes/merges to a specific staging branch (e.g.,release/*or a dedicatedstagingbranch).
- Deployment to staging is typically initiated manually via a GitHub Actions
- Process (GitHub Action
staging-deploy.yml):- The GitHub Action workflow is triggered.
- It checks out the specified commit/branch.
- It builds the Docker image, tagging it appropriately for staging (e.g.,
humlab-swedeb/swedeb-api:staging-latestorhumlab-swedeb/swedeb-api:staging-<commit-sha>). - It pushes the image to GitHub Container Registry (GHCR).
- It connects to the staging server via SSH (using secrets for credentials).
- On the staging server, it:
- Ensures the
docker-compose.ymlis up-to-date. - Ensures an
.env.stagingfile is present and correctly configured (this file might be managed on the server or its content injected via GitHub Actions secrets). - Sets the
SWEDEB_ENVIRONMENT=stagingvariable. - Pulls the new Docker image from GHCR.
- Runs
docker-compose -f docker-compose.yml --env-file .env.staging up -d --remove-orphans(or similar, ensuring it reads the.env.stagingby settingSWEDEB_ENVIRONMENTbefore the compose command).
- Ensures the
- Manual Fallback (if needed):
- SSH into the staging server.
- Set
export SWEDEB_ENVIRONMENT=staging. - Pull the latest image:
docker pull humlab-swedeb/swedeb-api:staging-tag. - Update
SWEDEB_IMAGE_TAGin.env.stagingif necessary. - Run
docker-compose up -d.
Deployed to the live production server.
- Trigger:
- Deployment to production is typically automated and triggered by:
- Pushing a new Git tag (e.g.,
v1.0.0). - Merging changes into the
mainbranch.
- Pushing a new Git tag (e.g.,
- Deployment to production is typically automated and triggered by:
- Process (GitHub Action
release.yml):- The GitHub Action workflow is triggered.
- It checks out the specific tag/commit from the
mainbranch. - It builds the Docker image, tagging it with the version and
latest(e.g.,humlab-swedeb/swedeb-api:v1.0.0andhumlab-swedeb/swedeb-api:prod-latest). - It pushes the image(s) to GHCR.
- It connects to the production server(s) via SSH.
- On the production server, it performs a similar sequence to staging:
- Ensures
docker-compose.ymland.env.productionare correct. - Sets
SWEDEB_ENVIRONMENT=production. - Pulls the new production-tagged Docker image.
- Runs
docker-compose -f docker-compose.yml --env-file .env.production up -d --remove-orphans. - May include additional steps like database migrations, health checks, or rolling updates if applicable.
- Ensures
docker-compose.yml: Can be checked into Git and pulled onto the server, or copied viascpduring deployment..env.<environment>files:- Option 1 (Recommended for security): Do not commit these to Git if they contain secrets.
- Create them manually on the server.
- Or, use a secrets management system (like HashiCorp Vault, or GitHub Actions encrypted secrets for CI/CD) to inject their content during deployment. For GitHub Actions, you can store the content of the
.envfile as a secret and write it to the server.
- Option 2 (If no sensitive data): Commit template/example files (
.env.example) and copy/rename them on the server, then populate values.
- Option 1 (Recommended for security): Do not commit these to Git if they contain secrets.
This strategy provides a clear path for code from development to production, leveraging Docker for consistency and GitHub Actions for automation where appropriate.