A practical, production-ready REST API built with FastAPI, PostgreSQL, and Docker. This project demonstrates modern Python API development with proper testing, database management, and containerization.
- FastAPI - Because it's fast, modern, and makes writing APIs actually enjoyable
- PostgreSQL - A reliable, battle-tested database that won't let you down
- Docker - So "it works on my machine" actually means it works everywhere
- Pytest - Testing shouldn't be painful, and with pytest, it isn't
The Docker Desktop interface showing our running containers. You can see the fastapi-crud container actively running with CPU and memory usage metrics displayed.
Terminal output showing all four services successfully built and started: fastapi-crud-web, Network, Container for database, and Container for web application.
Making a POST request to create a new note. The API returns a 201 Created status with the note data including the auto-generated ID.
Confirmation that all Docker Compose services are up and running smoothly.
The complete API interface with all CRUD operations: GET, POST, PUT, and DELETE endpoints for managing notes
Direct database verification using docker-compose exec to query PostgreSQL and confirm the note was actually persisted.
Got the FastAPI app running in Docker. The classic "hello world" moment, but containerized:
curl http://localhost:8000/
→ {"hello": "world"}Added PostgreSQL and hooked everything up with Docker Compose. Now the app and database talk to each other like old friends:
webservice running FastAPI on port 8000dbservice running PostgreSQL on port 5432- Both containers chatting away on the same network
Built the complete notes API with all four operations:
- POST
/notes/- Create a new note - GET
/notes/{id}/- Grab a specific note - PUT
/notes/{id}/- Update an existing note - DELETE
/notes/{id}/- Remove a note
And here's the best part - 12 tests, all passing:
docker-compose run --rm web python -m pytest -q
→ 12 passed in 1.09s ✨Started setting up Alembic for proper database version control. Because manually updating schemas is so 2010.
Just Docker and Docker Compose. That's it. No "but first install 37 dependencies" nonsense.
-
Clone and enter the project
cd fastapi-crud -
Fire it up
docker-compose up -d --build
-
Check it's alive
curl http://localhost:8000/
-
Explore the API docs Open your browser to
http://localhost:8000/docs- FastAPI generates beautiful, interactive docs automatically.
fastapi-crud/
├── app/
│ ├── main.py # FastAPI app and routes
│ ├── db.py # Database connection setup
│ └── models.py # SQLAlchemy models
├── tests/
│ ├── conftest.py # Test fixtures and setup
│ └── test_notes.py # API endpoint tests
├── Dockerfile # Container definition
├── docker-compose.yml # Multi-container orchestration
└── requirements.txt # Python dependencies
curl -X POST "http://localhost:8000/notes/" \
-H "Content-Type: application/json" \
-d '{"title":"My First Note","description":"This actually works!"}'curl http://localhost:8000/notes/1/curl -X PUT "http://localhost:8000/notes/1/" \
-H "Content-Type: application/json" \
-d '{"title":"Updated Title","description":"Changed my mind"}'curl -X DELETE http://localhost:8000/notes/1/Tests run inside Docker, so they use the same environment as production:
# Run all tests
docker-compose run --rm web python -m pytest
# Run with verbose output
docker-compose run --rm web python -m pytest -v
# Run with coverage
docker-compose run --rm web python -m pytest --cov=appWant to peek inside PostgreSQL?
# Jump into the database container
docker-compose exec db psql -U hello_fastapi -d hello_fastapi_dev
# Then run SQL
SELECT * FROM notes;- Finish Alembic setup and create initial migration
- Remove manual schema creation (let migrations handle it)
- Add migration commands to CI/CD
- Add JWT authentication (Stage 5)
- Create user management system
- Add integration tests with real database
- Set up GitHub Actions for automated testing
- Add API rate limiting
- Implement pagination for list endpoints
Docker Compose for Everything: Development, testing, and production use the same containers. No more "works on my machine" excuses.
Test-Driven Development: The tests came with the features, not after. All 12 tests passed on the first run because we built them alongside the API.
Database Mocking in Tests: Unit tests mock the database, so they're lightning-fast. Integration tests (coming soon) will use a real database.
Environment Variables: Configuration lives in docker-compose.yml, making it easy to change settings without touching code.
Port 8000 already in use?
docker-compose down
# or change the port in docker-compose.ymlDatabase connection errors? Wait a few seconds after starting - PostgreSQL needs a moment to initialize.
Tests failing? Make sure you rebuilt the Docker image after changing requirements:
docker-compose buildLast updated: November 12, 2025