{"id":48821857,"url":"https://github.com/louisbrulenaudet/api-template","last_synced_at":"2026-04-14T15:33:56.637Z","repository":{"id":345999431,"uuid":"1187911803","full_name":"louisbrulenaudet/api-template","owner":"louisbrulenaudet","description":"A minimal, production-ready template for building APIs with FastAPI, featuring strict data validation and Docker-based containerization, tailored for express deployment via a secure Cloudflare Tunnel 🚚⛅","archived":false,"fork":false,"pushed_at":"2026-04-05T09:29:42.000Z","size":215,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-05T11:21:09.934Z","etag":null,"topics":["agents","api","api-rest","claude-code","cloudflare","cloudflared","cursor","docker","docker-compose","fastapi","hackathon","pydantic","python","python-app","python-template","rest-api","ruff","template","template-generic-repo","uv"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/louisbrulenaudet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"louisbrulenaudet"}},"created_at":"2026-03-21T11:04:09.000Z","updated_at":"2026-04-05T09:28:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/louisbrulenaudet/api-template","commit_stats":null,"previous_names":["louisbrulenaudet/api-template"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/louisbrulenaudet/api-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louisbrulenaudet%2Fapi-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louisbrulenaudet%2Fapi-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louisbrulenaudet%2Fapi-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louisbrulenaudet%2Fapi-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/louisbrulenaudet","download_url":"https://codeload.github.com/louisbrulenaudet/api-template/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louisbrulenaudet%2Fapi-template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31803521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T11:13:53.975Z","status":"ssl_error","status_checked_at":"2026-04-14T11:13:53.299Z","response_time":153,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","api","api-rest","claude-code","cloudflare","cloudflared","cursor","docker","docker-compose","fastapi","hackathon","pydantic","python","python-app","python-template","rest-api","ruff","template","template-generic-repo","uv"],"created_at":"2026-04-14T15:33:55.751Z","updated_at":"2026-04-14T15:33:56.632Z","avatar_url":"https://github.com/louisbrulenaudet.png","language":"Python","funding_links":["https://github.com/sponsors/louisbrulenaudet"],"categories":[],"sub_categories":[],"readme":"# FastAPI starter with Pydantic validation, Docker, and Cloudflare Tunnel 🚚⛅\n\n[![FastAPI](https://img.shields.io/static/v1?label=framework\u0026message=FastAPI\u0026color=blue\u0026logo=fastapi\u0026logoColor=white)](https://fastapi.tiangolo.com/)\n[![Pydantic](https://img.shields.io/static/v1?label=validation\u0026message=Pydantic\u0026color=blue\u0026logo=pydantic\u0026logoColor=white)](https://docs.pydantic.dev/)\n[![Docker](https://img.shields.io/static/v1?label=deployment\u0026message=Docker\u0026color=blueviolet\u0026logo=docker\u0026logoColor=white)](https://www.docker.com/)\n[![uv](https://img.shields.io/static/v1?label=package%20manager\u0026message=uv\u0026color=blueviolet\u0026logo=uv\u0026logoColor=white)](https://docs.astral.sh/uv/)\n[![Ruff](https://img.shields.io/static/v1?label=linting\u0026message=Ruff\u0026color=blueviolet\u0026logo=ruff\u0026logoColor=white)](https://github.com/astral-sh/ruff)\n[![GitHub Actions](https://img.shields.io/static/v1?label=ci/cd\u0026message=GitHub%20Actions\u0026color=blueviolet\u0026logo=github-actions\u0026logoColor=white)](https://github.com/features/actions)\n\nA minimal, production-ready FastAPI template with strict request/response validation (Pydantic v2 settings and DTOs), Docker and Compose for local development and production-oriented deploys, and an optional Cloudflare Tunnel for a public HTTPS URL without exposing an inbound port on your host.\n\nUse the Makefile and **uv** for dependency management and day-to-day commands.\n\n## Tech Stack\n\n- **Language:** Python 3.14+ (strict type hints)\n- **Framework:** FastAPI (async web framework)\n- **Validation:** Pydantic v2 (data validation and settings management)\n- **HTTP Client:** httpx (async HTTP client)\n- **Caching:** aiocache (async caching)\n- **Formatting/Linting:** Ruff (fast Python linter and formatter)\n- **Package Manager:** uv (fast Python package installer and resolver)\n- **Build Tools:** Docker, Docker Compose\n- **Automation:** Makefile\n- **Environment:** python-dotenv (.env)\n- **Testing:** pytest, pytest-asyncio, pytest-cov\n\n## Project Structure\n\n```\n.\n├── app/\n│   ├── api/\n│   │   └── v1/\n│   │       ├── endpoints/\n│   │       │   └── base.py          # Health check endpoints (ping, health)\n│   │       └── router.py            # API router configuration\n│   ├── core/\n│   │   └── config.py                # Application settings and configuration\n│   ├── dtos/                        # Pydantic DTOs for request/response validation\n│   ├── enums/\n│   │   └── error_codes.py           # Centralized error code definitions\n│   ├── exceptions/\n│   │   ├── core_exception.py        # Base exception class with structured error handling\n│   │   └── client_initialization_error.py  # Client initialization error\n│   ├── utils/\n│   │   └── decorators.py            # Utility decorators (retry, async_retry)\n│   └── main.py                      # FastAPI application entry point with middleware\n├── make/\n│   ├── dev.mk                       # Development commands\n│   ├── docker.mk                    # Docker-related commands\n│   ├── help.mk                      # Help command implementation\n│   └── variables.mk                 # Makefile variables\n├── tests/                           # Test suite\n├── pyproject.toml                    # Project configuration, dependencies, and tool settings\n├── compose.yaml                     # Docker Compose (local development)\n├── Dockerfile                       # Docker image definition\n├── Makefile                         # Main Makefile with command shortcuts\n├── uv.lock                          # Locked dependency graph (canonical for uv, CI, and Docker)\n└── requirements.txt                 # Optional pip-style export (`make export-requirements`; `uv.lock` is canonical)\n```\n\n## Environment Configuration\n\n### Required Environment Variables\n\nThe application uses Pydantic Settings for configuration management. Required environment variables (defined in `app/core/config.py`):\n\n- `APP_NAME` (default: \"Backend\") - Application name\n- `API_KEY` - API key for authentication\n- `API_CLIENT` - API client identifier\n\n\u003e Note: The API key and API client identifier are not used in this template but are included for future use and example purposes.\n\n### Telemetry and tooling\n\nThis project avoids the FastAPI Cloud CLI stack (`fastapi-cloud-cli` / `sentry-sdk`) by depending on `fastapi-cli[standard-no-fastapi-cloud-cli]` with the same “standard” pieces as `fastapi[standard]`. Logfire export is disabled by default via environment variables in the Makefile, Docker, Compose, and CI. **uv** does not document a switch to turn off PyPI User-Agent metadata; see [astral-sh/uv#8474](https://github.com/astral-sh/uv/issues/8474).\n\n### Setup Instructions\n\n1. **Install dependencies:**\n\n   ```sh\n   make sync\n   ```\n\n   (`make install` is an alias for `sync`. The `dev` optional extra matches CI: `uv sync --locked --extra dev`.)\n\n2. **Configure environment:**\n\n   Copy `.env.template` to `.env` and fill in required variables:\n\n   ```\n   APP_NAME=Backend\n   ...\n   ```\n\n3. **(Optional) Run with Docker Compose**\n\n   Your `compose.yaml` uses `env_file: .env` to pass these values at **container start** (this is runtime configuration; it is not related to `.dockerignore`).\n\n   Example:\n\n   ```sh\n   docker compose up --build\n   # or\n   make docker-run-dev\n   ```\n\n   The app is published on **127.0.0.1:8000** on the host (loopback only), matching `make dev`. Use [http://127.0.0.1:8000](http://127.0.0.1:8000) or `localhost` from the same machine.\n\n   If you want to set values explicitly in YAML (not recommended for real secrets), you can use:\n\n   ```yaml\n   environment:\n     APP_NAME: \"Backend\"\n     ...\n   ```\n\n4. **(Optional) Cloudflare Tunnel (development sharing)**\n\n   To share the API without opening port `8000` on your LAN (e.g. for testing): set `TUNNEL_TOKEN` in `.env` and run `make docker-run-dev-tunnel` (tunnel is opt-in via the Compose profile `tunnel`). In the Compose workflow, `cloudflared` prints the public tunnel URL in the terminal (or use `make docker-tunnel-logs`).\n\n5. **Development:**\n\n   ```sh\n   make dev\n   ```\n\n   Default dev port is **8000** (`DEV_PORT` in [`make/variables.mk`](make/variables.mk)); Docker Compose dev uses the same port on the host.\n\n   - The API will be available at [http://localhost:8000](http://localhost:8000)\n   - Ping endpoint: [http://localhost:8000/api/v1/ping](http://localhost:8000/api/v1/ping)\n\n## Common Commands\n\nThe following Makefile commands are available for development, formatting, testing, and deployment:\n\n### Development Commands\n\n| Command                | Description                                 |\n|------------------------|---------------------------------------------|\n| `make dev`             | Run development server with hot reloading   |\n| `make test`            | Run the test suite with coverage            |\n| `make sync`            | Sync `.venv` from `uv.lock` (includes `dev` extra) |\n| `make sync-all`        | Sync with all optional extras                |\n| `make install`         | Alias for `make sync`                       |\n| `make lock`            | Lock project dependencies                   |\n| `make update`         | Update locked deps (`uv lock --upgrade` + sync) |\n| `make clean-venv`      | Remove local `.venv`                        |\n| `make type-check`      | Type check the source code using Ty         |\n| `make check`           | Run code quality checks (Ruff linting)      |\n| `make format`          | Format the codebase using Ruff              |\n| `make pre-commit`      | Run pre-commit checks on all files          |\n\n### Docker Commands\n\n| Command                | Description                                  |\n|------------------------|----------------------------------------------|\n| `make docker-check`    | Verify Docker installation and configuration |\n| `make docker-build`    | Create application containers                |\n| `make docker-rebuild`  | Rebuild containers with fresh configuration  |\n| `make docker-start`    | Launch application services                  |\n| `make docker-stop`     | Stop all running services                    |\n| `make docker-restart`  | Restart all application services             |\n| `make docker-logs`     | Display container logs                       |\n| `make docker-clean`    | Remove all containers and volumes            |\n| `make docker-run-dev`  | Start development server with live reload    |\n| `make docker-run-dev-tunnel`  | Start dev + Cloudflare Tunnel (opt-in)       |\n| `make docker-tunnel-logs`     | Follow Cloudflare Tunnel logs                |\n| `make docker-tunnel-stop`     | Stop Cloudflare Tunnel (keeps app)           |\n\nThe [`Dockerfile`](Dockerfile) exposes two targets: `runtime` (uvicorn, dependencies only—what CI builds) and `reload` (same dependency set as `runtime`, but runs `fastapi dev` with reload for local Compose). Optional `[dev]` extras (pytest, ruff, etc.) are for local/CI tooling, not installed in the image.\n\nThe [`.dockerignore`](.dockerignore) uses an **allowlist** strategy: everything is excluded by default (`*`) and only the three paths the Dockerfile actually copies are re-included — `pyproject.toml`, `uv.lock`, and `app/`. This keeps the build context minimal and ensures any file added to the repository in the future is automatically excluded without requiring a `.dockerignore` update.\n\n## Best Practices\n\n- Always validate request/response data using Pydantic models before processing\n- Always use DTO objects for data propagation during runtime\n- Implement comprehensive error handling with meaningful error messages\n- Use environment variables for configuration and secrets (never hardcode sensitive data)\n- Always run `make check` and `make format` before committing\n- Use Makefile for common tasks to ensure consistency across the team\n- Follow RESTful API design principles\n- Use utility decorators (`retry`, `async_retry`) for operations that may fail transiently\n- Implement proper async/await patterns throughout the application\n- Use dependency injection for testability and maintainability\n- Document all public functions and classes with docstrings\n\n- **Template / modular development:** Keep components modular and independent to enable parallel work and clean merges\n\n## Prerequisites\n\n- [Docker](https://docs.docker.com/get-docker/) and Docker Compose for containerization and deployment.\n- [uv](https://github.com/astral-sh/uv) (Python dependency manager)\n- [ruff](https://docs.astral.sh/ruff/) (linter/formatter)\n\nIn order to run the backend the fastest way possible, you can use the makefile setup and uv for Python dependency management as this:\n\n```sh\nmake sync\nmake update\nmake dev\n```\n\nThen you can ping the API at [http://127.0.0.1:8000/api/v1/ping](http://127.0.0.1:8000/api/v1/ping).\n\nIf you need to install packages such as transformers, you can do so with the following command:\n\n```sh\nuv add transformers\n```\n\n## Code Quality\n\n- Lint and check code:\n  ```sh\n  make check\n  ```\n\n- Format code:\n  ```sh\n  make format\n  ```\n\n- Type check:\n  ```sh\n  make type-check\n  ```\n\n## Citing this project\n\nIf you use this code in your research, please use the following BibTeX entry.\n\n```BibTeX\n@misc{louisbrulenaudet2026,\nauthor = {Louis Brulé Naudet},\ntitle = {A minimal, production-ready template for building APIs with FastAPI, featuring strict data validation and Docker-based containerization, tailored for express deployment via a secure Cloudflare Tunnel 🚚⛅},\nhowpublished = {\\url{https://github.com/louisbrulenaudet/api-template}},\nyear = {2026}\n}\n```\n\n---\n\n## Feedback\n\nIf you have any feedback, please reach out at [louisbrulenaudet@icloud.com](mailto:louisbrulenaudet@icloud.com).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flouisbrulenaudet%2Fapi-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flouisbrulenaudet%2Fapi-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flouisbrulenaudet%2Fapi-template/lists"}