Skip to content

Commit e493f03

Browse files
authored
Merge pull request #75 from febus982/docs-pages
Setup application documentation using github pages
2 parents c824f6a + 12aaa73 commit e493f03

File tree

7 files changed

+1223
-657
lines changed

7 files changed

+1223
-657
lines changed

.coveragerc

Lines changed: 0 additions & 12 deletions
This file was deleted.

.github/workflows/github-pages.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Deploy static content to Pages
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
# Allows you to run this workflow manually from the Actions tab
7+
workflow_dispatch:
8+
9+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
10+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
11+
concurrency:
12+
group: "pages"
13+
cancel-in-progress: false
14+
15+
jobs:
16+
build:
17+
18+
permissions:
19+
contents: read
20+
21+
environment:
22+
name: github-pages
23+
24+
runs-on: ubuntu-latest
25+
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v3
29+
30+
- name: Set up Python 3.12
31+
uses: actions/setup-python@v4
32+
with:
33+
python-version: "3.12"
34+
35+
- name: Install dependencies
36+
run: |
37+
python -m pip install --upgrade pip
38+
python -m pip install poetry
39+
poetry config virtualenvs.create false
40+
poetry install --no-root --with dev
41+
42+
- name: Build static pages
43+
run: make docs-build
44+
45+
- name: Setup Pages
46+
uses: actions/configure-pages@v4
47+
48+
- name: Upload artifact
49+
uses: actions/upload-pages-artifact@v3
50+
with:
51+
path: './site'
52+
53+
deploy:
54+
needs: build
55+
56+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
57+
permissions:
58+
pages: write # to deploy to Pages
59+
id-token: write # to verify the deployment originates from an appropriate source
60+
61+
environment:
62+
name: github-pages
63+
url: ${{ steps.deployment.outputs.page_url }}
64+
65+
runs-on: ubuntu-latest
66+
67+
steps:
68+
- name: Deploy to GitHub Pages
69+
id: deployment
70+
uses: actions/deploy-pages@v4

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.PHONY: docs docs-build
2+
13
containers:
24
# Use local UID to avoid files permission issues when mounting directories
35
# We could do this at runtime, by specifying the user, but it's easier doing it
@@ -73,3 +75,9 @@ generate-proto:
7375

7476
fix: format-fix lint-fix
7577
check: typing test format lint
78+
79+
docs:
80+
poetry run mkdocs serve
81+
82+
docs-build:
83+
poetry run mkdocs build

docs/index.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Bootstrap python service
2+
[![CI Pipeline](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/ci-pipeline.yml/badge.svg)](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/ci-pipeline.yml)
3+
[![Python 3.9](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.9.yml/badge.svg?event=push)](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.9.yml)
4+
[![Python 3.10](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.10.yml/badge.svg?event=push)](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.10.yml)
5+
[![Python 3.11](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.11.yml/badge.svg?event=push)](https://github.com/febus982/bootstrap-python-fastapi/actions/workflows/python-3.11.yml)
6+
7+
[![Maintainability](https://api.codeclimate.com/v1/badges/a2ab183e64778e21ae14/maintainability)](https://codeclimate.com/github/febus982/bootstrap-python-fastapi/maintainability)
8+
[![Test Coverage](https://api.codeclimate.com/v1/badges/a2ab183e64778e21ae14/test_coverage)](https://codeclimate.com/github/febus982/bootstrap-python-fastapi/test_coverage)
9+
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
10+
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
11+
12+
This is an example implementation of microservice applying
13+
concepts from [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
14+
and [SOLID principles](https://en.wikipedia.org/wiki/SOLID).
15+
16+
* The repository classes are isolated behind interfaces, enforcing the [Interface Segregation principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
17+
and the [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control) design pattern
18+
* The application frameworks are decoupled from the domain logic
19+
* The storage layer is decoupled from the domain logic
20+
21+
In this way our components are loosely coupled and the application logic
22+
(the domains package) is completely independent of the chosen framework
23+
and the persistence layer.
24+
25+
## HTTP API Docs and versioning
26+
27+
API documentation is provided by [FastAPI](https://fastapi.tiangolo.com/features/)
28+
on `/docs` and `/redoc` paths using OpenAPI format.
29+
30+
I believe that versioning an API at resource level provides a much more
31+
flexible approach than versioning the whole API.
32+
33+
The example `books` domain provides 2 endpoints to demonstrate this approach
34+
35+
* `/api/books/v1` (POST)
36+
* `/api/books/v2` (POST)
37+
38+
## Package layers
39+
40+
This application is structured following the principles of Clean Architecture.
41+
Higher level layers can import directly lower level layers. An inversion of control
42+
pattern has to be used for lower level layers to use higher level ones.
43+
44+
Packages are ordered from the highest level to the lowest one.
45+
46+
------
47+
48+
* `http_app` (http presentation layer)
49+
* `grpc_app` (grpc presentation layer)
50+
* `storage` (database connection manager, repository implementation)
51+
52+
------
53+
54+
* `domains` (services, repository interfaces)
55+
56+
------
57+
58+
## Class dependency schema
59+
60+
![](architecture.png)
61+
62+
## Data flow and layers responsibilities
63+
64+
![](flow.png)
65+
66+
## How to run
67+
68+
Using Docker:
69+
70+
* `make containers`: Build containers
71+
* `docker compose run --rm dev make migrate`: Run database migrations
72+
* `docker compose up dev`: Run HTTP application with hot reload
73+
* `docker compose up grpc`: Run GRPC application
74+
* `docker compose run --rm test`: Run test suite
75+
76+
Locally:
77+
78+
* `make migrate`: Run database migrations
79+
* `make install-dependencies`: Install requirements
80+
* `make dev-dependencies`: Install dev requirements
81+
* `make update-dependencies`: Updates requirements
82+
* `make migrate`: Run database migrations
83+
* `make dev`: Run HTTP application with hot reload
84+
* `make grpc`: Run GRPC application
85+
* `make test`: Run test suite
86+
87+
## Other commands for development
88+
89+
* `make generate-proto`: Generates grpcio python stubs from `.proto` files in `grpc_app/proto` directory
90+
* `make check`: Run tests, code style and lint checks
91+
* `make fix`: Run tests, code style and lint checks with automatic fixes (where possible)
92+
93+
## Multistage dockerfile configuration
94+
95+
Python docker image tend to become large after installing the application requirements
96+
(the slim base is ~150 MB uncompressed), therefore it's important to spend efforts
97+
to minimise the image size, even if it produces a slightly more complex multistage
98+
Dockerfile.
99+
100+
The following setup makes sure the production image will keep to a minimal size ("only" 390MB):
101+
* 150MB base image
102+
* 165MB python installed dependencies
103+
* 73MB poetry + updated pip
104+
105+
Using the following pipeline the "test" image is instead ~850MB, more than 400MB that would
106+
end up as a cost in traffic on each image pull.
107+
108+
![](docker-container.png)

mkdocs.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json
2+
3+
site_name: Bootstrap python fastapi
4+
site_description: 'A template for a python web service written applying Clean Architecture concepts'
5+
site_author: 'Federico Busetti'
6+
docs_dir: docs/
7+
repo_name: 'febus982/bootstrap-python-fastapi'
8+
repo_url: 'https://github.com/febus982/bootstrap-python-fastapi'
9+
10+
theme:
11+
name: material
12+
features:
13+
- navigation.expand
14+
- navigation.top
15+
- content.code.copy
16+
17+
palette:
18+
19+
# Palette toggle for light mode
20+
- scheme: default
21+
primary: teal
22+
toggle:
23+
icon: material/brightness-7
24+
name: Switch to dark mode
25+
26+
# Palette toggle for dark mode
27+
- scheme: slate
28+
primary: teal
29+
toggle:
30+
icon: material/brightness-4
31+
name: Switch to light mode
32+
33+
extra:
34+
social:
35+
- icon: fontawesome/brands/linkedin
36+
link: https://www.linkedin.com/in/federico-b-a0b78232
37+
38+
nav:
39+
- Home: index.md
40+
41+
markdown_extensions:
42+
- pymdownx.details
43+
- pymdownx.blocks.admonition
44+
- pymdownx.blocks.details
45+
- pymdownx.snippets
46+
- pymdownx.superfences

0 commit comments

Comments
 (0)