Skip to content

Mohammad-Hossein-Dlt/fastapi-mini-ecommerce

Repository files navigation

How dose it deploy? via docker-compose

How dose it deploy? via CI/CD and kubernetes

.env file parameters, put it next to the services

AUTH_BASE_URL = http://nginx-service/auth/api/v1
PRODUCT_BASE_URL = http://nginx-service/product/api/v1
ORDER_BASE_URL = http://nginx-service/order/api/v1

AUTH_DB_STACK = postgresql # postgresql, mongo_db
PRODUCT_DB_STACK = postgresql # postgresql, mongo_db
ORDER_DB_STACK = mongo_db # postgresql, mongo_db

MONGO_HOST = mongodb-service
MONGO_PORT = 27017
MONGO_INITDB_ROOT_USERNAME = root
MONGO_INITDB_ROOT_PASSWORD = rootpassword
MONGO_INITDB_DATABASE = db

POSTGRES_HOST = postgres-service
POSTGRES_PORT = 5432
POSTGRES_USER = admin
POSTGRES_PASSWORD = adminpassword
POSTGRES_DB = db

JWT_SECRET = 5fd4a7c9-7b61-49bf-8aea-ae8c53727290
JWT_ALGORITHM = HS256
JWT_EXPIRATION_MINUTES = 2
JWT_REFRESH_EXPIRATION_MINUTES = 4

GF_SECURITY_ADMIN_PASSWORD=admin

To run with docker-compose:

docker compose up -d

App architecture description

Infra Layer

In this layer, the application infrastructure is defined, such as:

  • Authentication utilities such as token creation, management, and validation

  • Database client and its models (tables)

  • Errors related to this layer and other layers

    • include status code and message
  • Services for interacting with external APIs

    • include interfaces and their implementation
  • Fastapi config such as

    • middleware
    • tasks that should be run on startup or shutdown, such as create and close database client
    • implement some states based on settings loaded from .env in main app, to have access them throughout the entire project
  • Mixin classes

  • Application settings load from the .env file

    • load with pydantic_settings
infra/
│
├── auth/
│   └── <files or directories...>
│
├── db/
│   ├── redis/
│   │   └── <files or directories...>
│   │
│   ├── mongodb/
│   │   └── <files or directories...>
│   │
│   └── sqlite/
│       └── <files or directories...>
│
├── exceptions/
│   └── <files...>
│
├── external_api/
│   ├── interface/
│   │   └── <files...>
│   │
│   └── service/
│       └── <files...>
│
├── fastapi_config/
│   └── <files...>
│
├── mixins/
│   └── <files...>
│
└── settings/
    └── <files...>

Domain Layer

In this layer, data models are defined that are only used inside the application, meaning between layers, for transferring data.

domain/
├── mock_data/
│   └── <files...>
│
└── schemas/
    └── <schema_group_name>/
       └── <files...>

Models Layer

In this layer, data models are defined that are only used for receiving or sending data to the client.

models/
├── filter/
│   └── <files...>
│
└── schemas/
    └── <schema_group_name>/
        └── <files...>

Repo Layer

In this layer, communication with the database is handled. Repository classes are defined here, whose methods provide interaction with the database. Each repository class inherits from an interface defined in this layer. Interfaces define the structure of database communication, so we can have multiple repository classes based on a single interface and use them for dependency injection.

repo/
├── interface/
│   └── <files...>
│
└── <implementation_name>/
    └── <files...>

Naming implementations can be based on:

  • Storage type — for example: sql, nosql
repo/
├── interface/
│   └── <files...>
│
├── sql/
│   └── <files...>
│
└── nosql/
    └── <files...>
  • Storage name — for example: postgresql, or mongodb.
repo/
├── interface/
│   └── <files...>
│
├── postgresql/
│   └── <files...>
│
└── mongodb/
    └── <files...>

Routes Layer

In this layer, endpoints are defined along with their dependencies, response statuses, and other endpoint-related configurations.

routes/
├── api_endpoints/
│   ├── <endpoint_group_name>/
│   │   └── <files...>
│   │
│   ├── <endpoint_group_name>/
│   │   └── <files...>
│   │
│   └── main_router.py
│
├── depends/
│   └── <files...>
│
└── http_response/
    └── <files...>

Usecase Layer

In this layer, the application’s business logic is defined. This layer acts as an important bridge between endpoints in the Routes layer, the database in the Repo layer, and external APIs in the Infra layer.

usecase/
├── <usecase_group_name>/
│   └── <files...>
│
└── <usecase_group_name>/
    └── <files...>

Note

The layers are not limited to the mentioned items and can also include other related configurations.

How dose it deploy? via docker-compose

Configuring Docker Compose

Services:

  • FastAPI app-services: Our application services -> auth-service, product-service, order-service, admin-service and user-service.
  • MongoDB service: Our NoSQL database, running on internal and external port 27017:27017.
  • PostgreSQL service: Our SQL database, running on internal port 5432.
  • pgAdmin service: Added for easier access to the PostgreSQL database. It runs on 8080:80, meaning we connect externally through port 8080 to the internal port 80.

Volumes: Both databases have their own storage volumes defined: pgdata and mongo_data.

Environment variables: All environment variables for the services are read from the .env file.

Restart policy: All services are set with restart: always. This ensures that whenever a container stops, it will automatically restart.

Service dependencies:

  • The database services don’t depend on any other services.
  • The FastAPI app depends on both database services. This means the databases must be fully created and running before the FastAPI app is built and started.
  • The pgAdmin service also depends on the PostgreSQL service.

FastAPI service details:

  • The build process for the FastAPI service starts with the Dockerfile located in the root directory of the app. This file copies the app’s files and directories into the container’s work directory (/app) and installs the required packages from requirements.txt.
  • The container ports for this service are defined in the .env file, and the ports section of the Docker Compose file references these environment variables.
  • Since we can change the default port of the FastAPI app via the .env file, the command to run the app is placed at the end of the service definition in the Docker Compose file. This way, the application always uses the internal port defined in .env.

How dose it deploy? via CI/CD and kubernetes

All Kubernetes manifests for our services, with databases services, nginx, prometheus, grafana and others, are organized and stored within the k8s directory in a structured manner.

Workflow configuration

  1. Environment setup:

    • All environment variables defined in the project repository’s Variables section are stored in a .env file.
  2. Docker registry login:

    • Authenticate with the Docker registry.
  3. Kubectl setup:

    • Configure and initialize kubectl with Kubeconfig, set in the secrets and access with secrets.KUBE_CONFIG.
  4. ConfigMap creation, generate all necessary ConfigMaps:

    • app-config – Contains environment variables from the .env file.
    • nginx-config – Built from the nginx.conf file for Nginx configuration.
    • prometheus-config – Built from the prometheus.yml file for Prometheus configuration.
  5. Secrets creation:

    • Create docker registry secrets for use in the imagePullSecrets section of the kubernetes manifests for our project services.
  6. Database services deployment:

    • Deploy database manifests first, to ensure database services are available.
  7. Build and push project services images:

    • Build docker images for all project services and push them to the registry.
  8. Project services deployment:

    • Deploy all project services using their kubernetes manifests.
  9. Other services deployment:

    • Finally, deploy the manifests for other services such as Nginx, Prometheus, and Grafana.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages