Skip to content

Commit 5ad56b4

Browse files
authored
Merge pull request #557 from nanotaboada/docs/556-normalize-readme-structure
docs(readme): normalize README structure
2 parents 342e663 + 4b4f197 commit 5ad56b4

File tree

2 files changed

+139
-206
lines changed

2 files changed

+139
-206
lines changed

README.md

Lines changed: 65 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,16 @@
1313
![Claude](https://img.shields.io/badge/Claude-contributing-D97757?logo=claude&logoColor=white&labelColor=181818)
1414
![CodeRabbit](https://img.shields.io/badge/CodeRabbit-reviewing-FF570A?logo=coderabbit&logoColor=white&labelColor=181818)
1515

16-
Proof of Concept for a RESTful API built with [Python 3](https://www.python.org/) and [FastAPI](https://fastapi.tiangolo.com/). Manage football player data with SQLite, SQLAlchemy 2.0 (async), Pydantic validation, and in-memory caching.
17-
18-
## Table of Contents
19-
20-
- [Features](#features)
21-
- [Tech Stack](#tech-stack)
22-
- [Project Structure](#project-structure)
23-
- [Architecture](#architecture)
24-
- [Architecture Decisions](#architecture-decisions)
25-
- [API Reference](#api-reference)
26-
- [Prerequisites](#prerequisites)
27-
- [Quick Start](#quick-start)
28-
- [Testing](#testing)
29-
- [Containers](#containers)
30-
- [Releases](#releases)
31-
- [Environment Variables](#environment-variables)
32-
- [Command Summary](#command-summary)
33-
- [Contributing](#contributing)
34-
- [Legal](#legal)
16+
Proof of Concept for a RESTful Web Service built with **FastAPI** and **Python 3.13**. This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Players resource (Argentina 2022 FIFA World Cup squad).
3517

3618
## Features
3719

38-
- 🏗️ **Modern async architecture** - Async/await throughout, Pydantic validation, and SQLAlchemy 2.0 patterns
39-
- 📚 **Interactive API exploration** - Auto-generated OpenAPI docs with FastAPI's built-in Swagger UI and `.rest` file for REST Client integration
40-
-**Performance optimizations** - Async SQLAlchemy, in-memory caching with aiocache (10-minute TTL), and efficient database operations
41-
- 🧪 **High test coverage** - Pytest suite with 80% minimum coverage and automated reporting to Codecov and SonarCloud
42-
- 📖 **Agent-optimized documentation** - Claude Code and GitHub Copilot instructions with coding guidelines, architecture rules, and agent workflows for AI-assisted development
43-
- 🐳 **Full containerization** - Production-ready Docker setup with Docker Compose orchestration
44-
- 🔄 **Complete CI/CD pipeline** - Automated linting (Black/Flake8), testing, Docker publishing, and GitHub releases
45-
- ♟️ **Coach-themed semantic versioning** - Memorable, alphabetical release names honoring legendary football coaches
20+
- 🏗️ **Async Architecture** - Async/await throughout with SQLAlchemy 2.0 and dependency injection via FastAPI's `Depends()`
21+
- 📚 **Interactive Documentation** - Auto-generated Swagger UI with VS Code and JetBrains REST Client support
22+
-**Performance Caching** - In-memory caching with aiocache and async SQLite operations
23+
-**Input Validation** - Pydantic models enforce request/response schemas with automatic error responses
24+
- 🐳 **Containerized Deployment** - Production-ready Docker setup with pre-seeded database
25+
- 🔄 **Automated Pipeline** - Continuous integration with Black, Flake8, and automated testing
4626

4727
## Tech Stack
4828

@@ -58,33 +38,6 @@ Proof of Concept for a RESTful API built with [Python 3](https://www.python.org/
5838
| **Linting / Formatting** | [Flake8](https://flake8.pycqa.org/) + [Black](https://black.readthedocs.io/) |
5939
| **Containerization** | [Docker](https://www.docker.com/) & [Docker Compose](https://docs.docker.com/compose/) |
6040

61-
## Project Structure
62-
63-
```text
64-
/
65-
├── main.py # Entry point: FastAPI setup, router registration
66-
├── routes/ # HTTP route definitions, dependency injection + caching
67-
│ ├── player_route.py
68-
│ └── health_route.py
69-
├── services/ # Async business logic
70-
│ └── player_service.py
71-
├── schemas/ # SQLAlchemy ORM models (database schema)
72-
│ └── player_schema.py
73-
├── databases/ # Async SQLAlchemy session setup
74-
│ └── player_database.py
75-
├── models/ # Pydantic models for request/response validation
76-
│ └── player_model.py
77-
├── tests/ # pytest integration tests
78-
│ ├── conftest.py
79-
│ ├── player_stub.py
80-
│ └── test_main.py
81-
├── rest/ # HTTP request files
82-
│ └── players.rest # CRUD requests (REST Client / JetBrains HTTP Client)
83-
├── storage/ # SQLite database file (pre-seeded)
84-
├── scripts/ # Container entrypoint & healthcheck
85-
└── .github/workflows/ # CI/CD pipelines
86-
```
87-
8841
## Architecture
8942

9043
Layered architecture with dependency injection via FastAPI's `Depends()` mechanism and Pydantic for request/response validation.
@@ -153,54 +106,29 @@ graph RL
153106
class tests test
154107
```
155108

156-
*Simplified, conceptual view — not all components or dependencies are shown.*
157-
158-
### Arrow Semantics
159-
160-
Arrows follow the injection direction: `A --> B` means A is injected into B. Solid arrows (`-->`) represent active dependencies — components wired via FastAPI's `Depends()` mechanism and invoked at runtime. Dotted arrows (`-.->`) represent structural dependencies — the consumer references types without invoking runtime behavior.
161-
162-
### Composition Root Pattern
163-
164-
`main` is the composition root: it creates the FastAPI application instance, configures the lifespan handler, and registers all route modules via `app.include_router()`. Dependencies are resolved at request time via FastAPI's `Depends()` mechanism.
165-
166-
### Layered Architecture
167-
168-
Four layers: Initialization (`main`), HTTP (`routes`), Business (`services`), and Data (`schemas`, `databases`).
169-
170-
Third-party packages are placed inside the subgraph of the layer that uses them — `FastAPI` and `aiocache` in HTTP, `SQLAlchemy` in Data. The soft dependency from `routes` to `SQLAlchemy` reflects `AsyncSession` appearing only as a type annotation in `Depends()`, with no direct SQLAlchemy calls at the route level.
171-
172-
`models` is a cross-cutting type concern — Pydantic request/response models consumed across all layers, with no logic of its own.
173-
174-
### Color Coding
175-
176-
Blue = core application packages, red = third-party libraries, green = tests.
109+
> *Arrows follow the injection direction (A → B means A is injected into B). Solid = runtime dependency, dotted = structural. Blue = core domain, red = third-party, green = tests.*
177110
178-
## Architecture Decisions
179-
180-
Key architectural decisions are documented as ADRs in [`docs/adr/`](docs/adr/README.md).
111+
Significant architectural decisions are documented in [`docs/adr/`](docs/adr/).
181112

182113
## API Reference
183114

184115
Interactive API documentation is available via Swagger UI at `http://localhost:9000/docs` when the server is running.
185116

186-
**Quick Reference:**
187-
188-
- `GET /players/` — List all players
189-
- `GET /players/{player_id}` — Get player by UUID (surrogate key)
190-
- `GET /players/squadnumber/{squad_number}` — Get player by squad number (natural key)
191-
- `POST /players/` — Create a new player
192-
- `PUT /players/squadnumber/{squad_number}` — Update an existing player
193-
- `DELETE /players/squadnumber/{squad_number}` — Remove a player
194-
- `GET /health` — Health check
195-
196-
### HTTP Requests
117+
| Method | Endpoint | Description | Status |
118+
| ------ | -------- | ----------- | ------ |
119+
| `GET` | `/players/` | List all players | `200 OK` |
120+
| `GET` | `/players/{player_id}` | Get player by ID | `200 OK` |
121+
| `GET` | `/players/squadnumber/{squad_number}` | Get player by squad number | `200 OK` |
122+
| `POST` | `/players/` | Create new player | `201 Created` |
123+
| `PUT` | `/players/squadnumber/{squad_number}` | Update player by squad number | `204 No Content` |
124+
| `DELETE` | `/players/squadnumber/{squad_number}` | Remove player by squad number | `204 No Content` |
125+
| `GET` | `/health` | Health check | `200 OK` |
197126

198-
A ready-to-use HTTP request file is available at [`rest/players.rest`](rest/players.rest). It covers all CRUD operations and can be run directly from your editor without leaving the development environment:
127+
Error codes: `400 Bad Request` (squad number mismatch on `PUT`) · `404 Not Found` (player not found) · `409 Conflict` (duplicate squad number on `POST`) · `422 Unprocessable Entity` (schema validation failed)
199128

200-
- **VS Code** — install the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension (`humao.rest-client`), open `rest/players.rest`, and click **Send Request** above any entry.
201-
- **JetBrains IDEs** (IntelliJ IDEA, PyCharm, WebStorm) — the built-in HTTP Client supports `.rest` files natively; no plugin required.
129+
For complete endpoint documentation with request/response schemas, explore the [interactive Swagger UI](http://localhost:9000/docs).
202130

203-
The file targets `http://localhost:9000` by default.
131+
Alternatively, use [`rest/players.rest`](rest/players.rest) with the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension for VS Code, or the built-in HTTP Client in JetBrains IDEs (IntelliJ IDEA, PyCharm, WebStorm).
204132

205133
## Prerequisites
206134

@@ -212,14 +140,14 @@ Before you begin, ensure you have the following installed:
212140

213141
## Quick Start
214142

215-
### Clone the repository
143+
### Clone
216144

217145
```bash
218146
git clone https://github.com/nanotaboada/python-samples-fastapi-restful.git
219147
cd python-samples-fastapi-restful
220148
```
221149

222-
### Install dependencies
150+
### Install
223151

224152
Dependencies are defined in `pyproject.toml` using [PEP 735](https://peps.python.org/pep-0735/) dependency groups.
225153

@@ -233,135 +161,51 @@ source .venv/bin/activate # On Windows: .venv\Scripts\activate
233161
uv pip install --group dev
234162
```
235163

236-
Or with specific groups:
237-
238164
| Command | Description |
239165
| ------- | ----------- |
240166
| `uv pip install` | Production dependencies only |
241167
| `uv pip install --group test` | Test dependencies |
242168
| `uv pip install --group lint` | Linting dependencies |
243169
| `uv pip install --group dev` | All (test + lint + production) |
244170

245-
### Start the development server
171+
### Run
246172

247173
```bash
248174
uv run uvicorn main:app --reload --port 9000
249175
```
250176

251-
The server will start on `http://localhost:9000`.
252-
253-
### Access the application
254-
255-
- **API:** `http://localhost:9000`
256-
- **Swagger Documentation:** `http://localhost:9000/docs`
257-
- **Health Check:** `http://localhost:9000/health`
177+
### Access
258178

259-
## Testing
179+
Once the application is running, you can access:
260180

261-
Run the test suite with coverage:
262-
263-
```bash
264-
# Run all tests
265-
uv run pytest
266-
267-
# Run tests with verbose output
268-
uv run pytest -v
269-
270-
# Run tests with coverage report
271-
uv run pytest --cov=./ --cov-report=term
272-
```
273-
274-
Tests are located in the `tests/` directory and use `httpx` for async integration testing. Coverage reports are generated for routes, services, and databases.
275-
276-
**Coverage target:** 80% minimum.
181+
- **API Server**: `http://localhost:9000`
182+
- **Swagger UI**: `http://localhost:9000/docs`
183+
- **Health Check**: `http://localhost:9000/health`
277184

278185
## Containers
279186

280-
This project includes full Docker support with Docker Compose for easy deployment.
281-
282-
### Build the Docker image
283-
284-
```bash
285-
docker compose build
286-
```
287-
288-
### Start the application
187+
### Build and Start
289188

290189
```bash
291190
docker compose up
292191
```
293192

294-
> 💡 On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.
193+
> 💡 **Note:** On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.
295194
296-
### Stop the application
195+
### Stop
297196

298197
```bash
299198
docker compose down
300199
```
301200

302-
### Reset the database
201+
### Reset Database
303202

304203
To remove the volume and reinitialize the database from the built-in seed file:
305204

306205
```bash
307206
docker compose down -v
308207
```
309208

310-
The containerized application runs on port 9000 and includes health checks that monitor the `/health` endpoint.
311-
312-
## Releases
313-
314-
This project uses famous football coaches as release codenames ♟️, following an A-Z naming pattern.
315-
316-
### Release Naming Convention
317-
318-
Releases follow the pattern: `v{SEMVER}-{COACH}` (e.g., `v1.0.0-ancelotti`)
319-
320-
- **Semantic Version**: Standard versioning (MAJOR.MINOR.PATCH)
321-
- **Coach Name**: Alphabetically ordered codename from the [famous coach list](CHANGELOG.md)
322-
323-
### Create a Release
324-
325-
To create a new release, follow this workflow:
326-
327-
#### 1. Create a Release Branch
328-
329-
```bash
330-
git checkout -b release/v1.0.0-ancelotti
331-
```
332-
333-
#### 2. Update CHANGELOG.md
334-
335-
Document your changes in [CHANGELOG.md](CHANGELOG.md):
336-
337-
```bash
338-
# Move items from [Unreleased] to new release section
339-
# Example: [1.0.0 - Ancelotti] - 2026-02-15
340-
git add CHANGELOG.md
341-
git commit -m "docs(changelog): release v1.0.0 Ancelotti"
342-
git push origin release/v1.0.0-ancelotti
343-
```
344-
345-
#### 3. Create and Push Tag
346-
347-
Then create and push the version tag:
348-
349-
```bash
350-
git tag -a v1.0.0-ancelotti -m "Release 1.0.0 - Ancelotti"
351-
git push origin v1.0.0-ancelotti
352-
```
353-
354-
#### 4. Automated CD Workflow
355-
356-
This triggers the CD workflow which automatically:
357-
358-
1. Validates the coach name
359-
2. Builds and tests the project with coverage
360-
3. Publishes Docker images to GitHub Container Registry with three tags
361-
4. Creates a GitHub Release with auto-generated changelog from commits
362-
363-
> 💡 Always update CHANGELOG.md before creating the tag. See [CHANGELOG.md](CHANGELOG.md) for detailed release instructions.
364-
365209
### Pull Docker Images
366210

367211
Each release publishes multiple tags for flexibility:
@@ -377,29 +221,52 @@ docker pull ghcr.io/nanotaboada/python-samples-fastapi-restful:ancelotti
377221
docker pull ghcr.io/nanotaboada/python-samples-fastapi-restful:latest
378222
```
379223

380-
> 💡 See [CHANGELOG.md](CHANGELOG.md) for the complete coach list (A-Z) and release history.
381-
382224
## Environment Variables
383225

384-
The application can be configured using the following environment variables (declared in [`compose.yaml`](compose.yaml)):
385-
386226
```bash
387227
# Database storage path (default: ./storage/players-sqlite3.db)
388-
# In Docker: /storage/players-sqlite3.db
389228
STORAGE_PATH=./storage/players-sqlite3.db
390229

391230
# Python output buffering: set to 1 for real-time logs in Docker
392231
PYTHONUNBUFFERED=1
393232
```
394233

234+
## Contributing
235+
236+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on:
237+
238+
- Code of Conduct
239+
- Development workflow and best practices
240+
- Commit message conventions (Conventional Commits)
241+
- Pull request process and requirements
242+
243+
**Key guidelines:**
244+
245+
- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages
246+
- Ensure all tests pass (`uv run pytest`)
247+
- Run `uv run black .` before committing
248+
- Keep changes small and focused
249+
- Review `.github/copilot-instructions.md` for architectural patterns
250+
251+
**Testing:**
252+
253+
Run the test suite with pytest:
254+
255+
```bash
256+
# Run all tests
257+
uv run pytest
258+
259+
# Run tests with coverage report
260+
uv run pytest --cov=./ --cov-report=term
261+
```
262+
395263
## Command Summary
396264

397265
| Command | Description |
398266
| ------- | ----------- |
399267
| `uv run uvicorn main:app --reload --port 9000` | Start development server |
400268
| `uv pip install --group dev` | Install all dependencies |
401269
| `uv run pytest` | Run all tests |
402-
| `uv run pytest -v` | Run tests with verbose output |
403270
| `uv run pytest --cov=./ --cov-report=term` | Run tests with coverage |
404271
| `uv run flake8 .` | Lint code |
405272
| `uv run black --check .` | Check formatting |
@@ -408,17 +275,9 @@ PYTHONUNBUFFERED=1
408275
| `docker compose up` | Start Docker container |
409276
| `docker compose down` | Stop Docker container |
410277
| `docker compose down -v` | Stop and remove Docker volume |
411-
412-
## Contributing
413-
414-
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct and the process for submitting pull requests.
415-
416-
**Key guidelines:**
417-
418-
- Follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages
419-
- Ensure all tests pass (`uv run pytest`)
420-
- Run `uv run black .` before committing
421-
- Keep changes small and focused
278+
| **AI Commands** | |
279+
| `/pre-commit` | Runs linting, tests, and quality checks before committing |
280+
| `/pre-release` | Runs pre-release validation workflow |
422281

423282
## Legal
424283

0 commit comments

Comments
 (0)