Skip to content

Commit

Permalink
init backend microservcie based on FastAPI
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanprytula committed Dec 16, 2024
1 parent dba47bf commit 9d3915e
Show file tree
Hide file tree
Showing 76 changed files with 4,036 additions and 5 deletions.
27 changes: 27 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ site/

# Tools caches
.ruff_cache/
.pytest_cache/

.vscode/

sandbox/
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,27 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

#### `backend` microservice: bootstrapped from `fastapi/full-stack-fastapi-template`

MIT License

Copyright (c) 2019 Sebastián Ramírez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
# By declaring a target as .PHONY, you ensure that Make will run the associated commands every time you invoke that target,
# regardless of whether a file with the same name exists. This prevents any potential confusion if a file named <some_name>
# were to be created in the future.

.PHONY: help

help: ## Show this help (color=yes)
@grep --extended-regexp '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'





add-dev-gateway: ## e.g., make add-dev-gateway dep=mypy
uv --directory microservices/gateway add --dev $(dep)
52 changes: 47 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ Starting with Python frameworks and tools. Future - add more frameworks and tool
project-root/
├── microservices/
│ ├── gateway/ # FastAPI-based API gateway
│ ├── backend/ # FastAPI-based public/private APIs
│ ├── admin_panel/ # Django-based admin panel
│ ├── api/ # FastAPI-based public/private APIs
│ ├── etl/ # Flask-based data pipelines
│ ├── dashboard/ # Streamlit-based dashboard/visualization
│ ├── data_pipelines/ # Flask-based data pipelines
│ ├── data_visualizations/ # Streamlit-based dashboard/visualization
├── shared/
│ ├── auth/ # Shared Python libraries (e.g., authentication)
│ ├── libs/ # Shared Python libraries (e.g., logging)
│ ├── libs/ # Shared Python libraries (e.g., logging, error_handling)
│ ├── contracts/ # API contracts (e.g., OpenAPI specs)
│ ├── models/ # Shared Pydantic/Django models or schema definitions
│ ├── utils/ # Shared Python libraries (e.g., utilities)
| |── data_processing/ # Shared data processing logic (ETL transformations)
│ ├── message_broker/ # Kafka/RabbitMQ message producers and consumers
├── infra/
│ ├── docker/ # Dockerfiles for services
Expand Down Expand Up @@ -125,3 +126,44 @@ The key is to maintain a single repository's branching model where the overall c
5. Directory-Specific Considerations:
1. Shared libraries (e.g., `shared/auth`): If changes in these shared components affect multiple microservices, feature branches related to these can also exist, such as `feature/shared-auth`.
2. Terraform: Infrastructure changes can follow the same process, such as `feature/terraform-update`. This allows you to deploy infrastructure changes in parallel with service features.

### Shell commands heap

TODO: sort later

### Development

```shell
# Enter needed microservice directory
docker compose up --build


# option 1: automatically grabs compose.yaml and compose.override.yaml files
docker compose watch

# option 2: implicit set
docker compose -f compose.yaml -f compose.admin.yaml run backup_db


```

Generate Secret Keys

```shell
python -c "import secrets; print(secrets.token_urlsafe(32))"
export POSTGRES_PASSWORD=$(echo "pymicromax-password" | openssl passwd -6 -stdin)
```

#### Init DB scripts

Behavior Explanation:

- Volume `app-db-data`: This stores the database data persistently. If this volume already exists, initialization scripts won't run again unless the volume is deleted.
- Initialization Scripts: Any `.sql` or `.sh` script in /docker-entrypoint-initdb.d will execute only during the first startup of the container (if the data directory is empty).
- Check for Database: The SQL script ensures the database is created only if it doesn't already exist.

```shell
docker compose down
docker volume rm <project_name>_app-db-data
docker compose up
```
13 changes: 13 additions & 0 deletions infra/docker/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# services:

# web:
# build: .
# depends_on:
# db:
# condition: service_healthy
# restart: true
# redis:
# condition: service_started

# redis:
# image: redis
Empty file added infra/iac/terraform/.gitkeep
Empty file.
Empty file added infra/k8s/deployments/.gitkeep
Empty file.
Empty file added infra/k8s/services/.gitkeep
Empty file.
Empty file added infra/secrets/.gitkeep
Empty file.
9 changes: 9 additions & 0 deletions microservices/backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Python
__pycache__
app.egg-info
*.pyc
.mypy_cache
.pytest_cache
.coverage
htmlcov
.venv
43 changes: 43 additions & 0 deletions microservices/backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
FROM python:3.13

ENV PYTHONUNBUFFERED=1

WORKDIR /app/

# Install uv
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
COPY --from=ghcr.io/astral-sh/uv:0.5.1 /uv /bin/uv

# Place executables in the environment at the front of the path
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#using-the-environment
ENV PATH="/app/.venv/bin:$PATH"

# Compile bytecode
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#compiling-bytecode
ENV UV_COMPILE_BYTECODE=1

# uv Cache
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#caching
ENV UV_LINK_MODE=copy

# Install dependencies
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project

ENV PYTHONPATH=/app

COPY ./scripts /app/scripts

COPY ./pyproject.toml ./uv.lock ./alembic.ini /app/

COPY ./app /app/app

# Sync the project
# Ref: https://docs.astral.sh/uv/guides/integration/docker/#intermediate-layers
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync

CMD ["fastapi", "run", "--workers", "4", "app/main.py"]
117 changes: 117 additions & 0 deletions microservices/backend/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
# Use forward slashes (/) also on windows to provide an os agnostic path
script_location = app/alembic

# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
# for all available tokens
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s

# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .

# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python>=3.9 or backports.zoneinfo library.
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
# string value is passed to ZoneInfo()
# leave blank for localtime
# timezone =

# max length of characters to apply to the "slug" field
# truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; This defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator" below.
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions

# version path separator; As mentioned above, this is the character used to split
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
# Valid values for version_path_separator are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
# version_path_separator = newline
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.

# set to 'true' to search source files recursively
# in each "version_locations" directory
# new in Alembic version 1.10
# recursive_version_locations = false

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8

# sqlalchemy.url = driver://user:pass@localhost/dbname


[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples

# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME

# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
# hooks = ruff
# ruff.type = exec
# ruff.executable = %(here)s/.venv/bin/ruff
# ruff.options = --fix REVISION_SCRIPT_FILENAME

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARNING
handlers = console
qualname =

[logger_sqlalchemy]
level = WARNING
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
Empty file.
1 change: 1 addition & 0 deletions microservices/backend/app/alembic/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
Loading

0 comments on commit 9d3915e

Please sign in to comment.