Monastery Web API is a production‑oriented, containerized RESTful web service for managing monastery records. Built with Flask, SQLAlchemy (ORM) and MySQL, the project includes database migrations, unit and integration tests, Swagger documentation, and a Docker Compose setup for reproducible local and CI environments.
- RESTful CRUD endpoints for monastery resources: GET, POST, PUT, PATCH, DELETE
- SQLAlchemy ORM models with validation and convenience methods (
save,update,delete,to_dict) - Flask‑Migrate (Alembic) for versioned database migrations
- Swagger / Flasgger UI at
/apidocsfor interactive API exploration - Consistent JSON error handling via typed exceptions and structured responses
- Unit and integration tests covering routes and model behavior
- Containerized stack with
Dockerfileanddocker-compose.ymland production WSGI via Gunicorn
Application
app.py— Flask application and route definitions with Swagger annotationsModels/Monastery.py— SQLAlchemy model encapsulating persistence and validationexceptions.py— typed exceptions with logging and consistent JSON payloads
Persistence
- MySQL as the primary datastore
- Migrations managed by Flask‑Migrate to evolve schema safely
- Docker volume for persistent database storage in local/dev environments
Deployment
- Dockerfile builds a minimal Python image and runs Gunicorn
- docker-compose.yml orchestrates
monastery_apiandmonastery_dbfor local development and CI - Designed for portability to cloud/container platforms with minimal changes
git clone https://github.com/MIhajloS07/Monastery-Web-API.git
cd Monastery-Web-APIdocker compose up -d --build
docker compose ps
http://localhost:5000/api/monasteries
http://localhost:5000/apidocs
docker compose down
docker compose down -v
- SQLALCHEMY_DATABASE_URI — SQLAlchemy connection string (default provided in
docker-compose.yml) - MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD — configured in
docker-compose.yml
- Use a .env file or CI secrets to override sensitive values.
- When running via Compose, ensure SQLALCHEMY_DATABASE_URI points to the Compose service name, for example:
mysql+pymysql://user:password@db:3306/monastery
# create a migration after model changes
docker compose exec monastery_api flask db migrate -m "describe change"
# apply migrations
docker compose exec monastery_api flask db upgradedocker compose exec monastery_api python -m unittest discover -s tests-
docker compsoe up -d --build
-
docker compose exec monastery_api flask db upgrade -
docker compose exec monastery_api python -m unittest discover -s tests -
docker compose down -v
curl -X POST http://localhost:5000/api/monasteries \
-H "Content-Type: application/json" \
-d '{
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190,
}'
{
"id": 1,
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190,
}
curl http://localhost:5000/api/monasteries
[
{
"id": 1,
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190
},
{
"id": 2,
"name": "Sopoćani",
"location": "Raška, Serbia",
"year_of_construction": 1260
}
]
curl http://localhost:5000/api/monasteries
[
{
"id": 1,
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190
},
{
"id": 2,
"name": "Sopoćani",
"location": "Raška, Serbia",
"year_of_construction": 1260
}
]
curl http://localhost:5000/api/monasteries/1
{
"id": 1,
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190,
}
{ "error": "Monastery not found", "status": 404 }
curl -X PUT http://localhost:5000/api/monasteries/1 \
-H "Content-Type: application/json" \
-d '{
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190,
}'
{
"id": 1,
"name": "Studenica",
"location": "Kraljevo, Serbia",
"year_of_construction": 1190,
}
curl -X PATCH http://localhost:5000/api/monasteries/1 \
-H "Content-Type: application/json" \
-d '{"location":"New Location, Serbia"}'
{
"id": 1,
"name": "Studenica",
"location": "New Location, Serbia",
"year_of_construction": 1190
}
curl -X DELETE http://localhost:5000/api/monasteries/1
curl -X POST http://localhost:5000/api/monasteries \
-H "Content-Type: application/json" \
-d '{"name": "", "location": "X"}'
{
"error": "Validation failed",
"details": {
"name": "Name must not be empty",
"year_of_construction": "Year is required"
},
"status": 400
}
Open the interactive API documentation to try endpoints and view schemas:
http://localhost:5000/apidocs
- Presentation Layer → Client (Web)
- Business Logic Layer → Flask application (
app.py) + Swagger UI - Persistence Layer → Model (Monastery) + MySQL Server
- Docker → monastery_api container (Flask + Gunicorn) + monastery_db container (MySQL)
📂 monastery-api/
├── 📂 migrations/ # Alembic migrations (versions, env.py, script templates)
│ ├── versions/ # Database migration history
│ ├── alembic.ini # Alembic configuration
│ ├── env.py # Migration environment setup
│ └── script.py.mako # Template for generating migrations
│
├── 📂 Models/ # ORM models
│ ├── init.py # Package initializer
│ └── Monastery.py # Monastery entity model
│
├── 📂 tests/ # Unit and integration tests
│ ├── test_api.py # Tests for API routes
│ └── test_monastery_model.py # Tests for Monastery model
│
├── app.py # Main Flask application (Business Logic Layer)
├── exceptions.py # Custom exception handling
├── requirements.txt # Python dependencies
├── docker-compose.yml # Docker orchestration (API + DB containers)
├── Dockerfile # Build definition for monastery_api container
├── .env # Environment variables (DB URL, secrets)
├── .dockerignore # Files ignored during Docker build
├── .gitignore # Files ignored by Git
├── LICENSE # Project license
├── README.md # Documentation (badges, architecture, setup)
└── errors.log # Error log file
- migrations → Database versioning with Alembic.
- Models → SQLAlchemy ORM models, e.g.
Monastery.py. - tests → Unit and integration tests for API and models.
- app.py → Main Flask application, routes, Swagger UI.
- exceptions.py → Centralized error handling.
- docker-compose.yml + Dockerfile → Container orchestration and build.
- requirements.txt → Project dependencies.
- .env → Environment configuration (e.g. DB connection).
- Keep .env out of version control; include .env.example with non-sensitive defaults.
- Split tests into unit and integration to separate fast model tests from end‑to‑end API tests.
- Consider adding a top‑level Makefile or scripts/ entries for common tasks (start, test, migrate, seed).
This project is licensed under the MIT License — see the LICENSE file in the repository for full terms.