Skip to main content
FastAPI RealWorld Example
  1. Projects/

FastAPI RealWorld Example

Luiz Carlos Cosmi Filho
Author
Luiz Carlos Cosmi Filho
Software Developer

Overview
#

A implementation of the RealWorld specification, a blogging platform similar to Medium, built with FastAPI. The project integrates a full observability stack, hardened container images, and automated CI/CD pipelines. It serves as a reference for building scalable, maintainable, and observable Python backend services.

sequenceDiagram
    participant User
    participant Conduit Backend
    participant PostgreSQL
    participant Otel Collector
    participant Jaeger
    participant OpenSearch
    participant Prometheus
    participant Grafana

    User->>Conduit Backend: Requests
    Conduit Backend->>PostgreSQL: Interacts with database
    Conduit Backend->>User: Responses
    Conduit Backend->>Otel Collector: Exposes metrics, traces, and logs
    Otel Collector->>Jaeger: Stores traces
    Otel Collector->>OpenSearch: Stores logs
    Otel Collector->>Prometheus: Stores metrics
    Jaeger->>Grafana: Provides traces
    OpenSearch->>Grafana: Provides logs
    Prometheus->>Grafana: Provides metrics
    Grafana->>User: Displays monitoring dashboard

Backend
#

The API is built with FastAPI following a layered architecture: routes, service, models, schemas, and core configuration. Data persistence uses PostgreSQL with SQLModel as the ORM, combining SQLAlchemy 2.0 async engine with Pydantic v2 validation, and Alembic for schema migrations.

Authentication is implemented with JWT, and the codebase enforces static typing throughout using mypy, with flake8 and isort for linting and import ordering enforced via pre-commit hooks.

Observability
#

The entire observability stack is instrumented through OpenTelemetry, with the collector routing signals to dedicated backends:

  • Traces: Jaeger for distributed tracing across requests
  • Metrics: Prometheus for time series collection exposed via /metrics
  • Logs: OpenSearch for structured log aggregation and querying
  • Dashboards: Grafana for unified visualization of all signals

This setup mirrors a real production environment, allowing end to end traceability from HTTP request to database query.

graph TB
subgraph tdf[Telemetry Data Flow]
    subgraph subgraph_padding [ ]
        style subgraph_padding fill:none,stroke:none;
        subgraph od[Conduit]
        ms(FastAPI Backend)
        end

        ms -.->|"OTLP
gRPC"| oc-grpc subgraph oc[OTel Collector] style oc fill:#97aef3,color:black; oc-grpc[/"OTLP Receiver
listening on
grpc://localhost:4317"/] oc-proc(Processors) oc-spanmetrics[/"Span Metrics Connector"/] oc-prom[/"OTLP HTTP Exporter"/] oc-otlp[/"OTLP Exporter"/] oc-opensearch[/"OpenSearch Exporter"/] oc-grpc --> oc-proc oc-proc --> oc-prom oc-proc --> oc-otlp oc-proc --> oc-opensearch oc-proc --> oc-spanmetrics oc-spanmetrics --> oc-prom end oc-prom -->|"localhost:9090/api/v1/otlp"| pr-sc oc-otlp -->|gRPC| ja-col oc-opensearch -->|HTTP| os-http subgraph pr[Prometheus] style pr fill:#e75128,color:black; pr-sc[/"Prometheus OTLP Write Receiver"/] pr-tsdb[(Prometheus TSDB)] pr-http[/"Prometheus HTTP
listening on
localhost:9090"/] pr-sc --> pr-tsdb pr-tsdb --> pr-http end pr-b{{"Browser
Prometheus UI"}} pr-http ---->|"localhost:9090/graph"| pr-b subgraph ja[Jaeger] style ja fill:#60d0e4,color:black; ja-col[/"Jaeger Collector
listening on
grpc://jaeger:4317"/] ja-db[(Jaeger DB)] ja-http[/"Jaeger HTTP
listening on
localhost:16686"/] ja-col --> ja-db ja-db --> ja-http end subgraph os[OpenSearch] style os fill:#005eb8,color:black; os-http[/"OpenSearch
listening on
localhost:9200"/] os-db[(OpenSearch Index)] os-http ---> os-db end subgraph gr[Grafana] style gr fill:#f8b91e,color:black; gr-srv["Grafana Server"] gr-http[/"Grafana HTTP
listening on
localhost:3000"/] gr-srv --> gr-http end pr-http --> |"localhost:9090/api"| gr-srv ja-http --> |"localhost:16686/api"| gr-srv os-http --> |"localhost:9200/api"| gr-srv ja-b{{"Browser
Jaeger UI"}} ja-http ---->|"localhost:16686/search"| ja-b gr-b{{"Browser
Grafana UI"}} gr-http -->|"localhost:3000/dashboard"| gr-b end end

DevOps
#

The full stack, including application, database, and observability infrastructure, is orchestrated with Docker Compose for a single command local deployment. The project also explores different container image strategies to address security and image size concerns:

  • Standard: conventional single layer image
  • Multistage: optimized multistage build separating dependencies from runtime
  • Distroless: minimal runtime without shell or package manager
  • Chainguard: hardened baseline with minimal attack surface

CI/CD is handled by GitHub Actions, automating test runs and publishing Docker images to Docker Hub on each release. Dependency updates are managed automatically via Dependabot.