API REST de pilotage du réseau mobile : gestion des antennes et des interventions terrain.
- Docker & Docker Compose ou Python 3.11+ avec PostgreSQL local
curl(pour les exemples ci-dessous)
docker-compose up --buildL'application démarre sur http://localhost:8000. Les migrations Alembic et le seed de données de démonstration (5 antennes) s'exécutent automatiquement au démarrage — les exemples curl ci-dessous fonctionnent donc immédiatement.
Documentation interactive : http://localhost:8000/docs
# 1. Créer et activer le virtualenv
python3 -m venv .venv
source .venv/bin/activate
# 2. Installer les dépendances
pip install -r requirements.txt
# 3. Configurer les variables d'environnement
cp .env.example .env
# Éditer .env avec votre DATABASE_URL et API_KEY# 4. Appliquer les migrations
alembic upgrade head
# 5. Insérer les données de démonstration
python3 -m app.seed
# 6. Démarrer l'API
uvicorn app.main:app --reload| Variable | Exemple | Description |
|---|---|---|
DATABASE_URL | postgresql+asyncpg://postgres:postgres@localhost:5432/antennas | URL de connexion PostgreSQL |
API_KEY | changeme-super-secret-key | Clé d'authentification API |
Les tests requièrent une base antennas_test (même hôte que DATABASE_URL) :
# Créer la base de test (une seule fois)
createdb antennas_test
# ou via Docker : docker exec -it <db-container> psql -U postgres -c "CREATE DATABASE antennas_test;"# Lancer la suite de tests
pytest -vcurl http://localhost:8000/api/v1/antennasAvec filtres et pagination :
curl "http://localhost:8000/api/v1/antennas?city=Paris&status=UP&limit=10&offset=0"curl -X POST http://localhost:8000/api/v1/intervention \
-H "Authorization: Bearer changeme-super-secret-key" \
-H "Content-Type: application/json" \
-d '{ "antenna_id": 1, "description": "Panne secteur — remplacement carte alimentation", "technician_identity": "Jean Dupont", "priority": "HIGH" }'L'antenne passe automatiquement à DOWN.
Utilisez l'id renvoyé par le POST précédent (2 en suivant ce déroulé — l'intervention 1 est celle du seed, déjà clôturée) :
curl -X PATCH http://localhost:8000/api/v1/intervention/2/close \
-H "Authorization: Bearer changeme-super-secret-key"L'antenne repasse automatiquement à UP.
curl -X POST http://localhost:8000/api/v1/intervention \
-H "Content-Type: application/json" \
-d '{"antenna_id": 1, "description": "test", "technician_identity": "X", "priority": "LOW"}'FastAPI a été retenu pour sa performance native en I/O asynchrone (ASGI), sa validation automatique via Pydantic et la génération OpenAPI sans configuration supplémentaire. SQLAlchemy 2.0 async avec asyncpg permet de tirer parti de l'async bout-en-bout, depuis la requête HTTP jusqu'à la base de données.
La protection contre la double intervention active repose sur deux mécanismes complémentaires :
Index partiel unique PostgreSQL (défense au niveau base) :
CREATEUNIQUE INDEXuq_one_active_interventionON interventions (antenna_id) WHERE ended_at IS NULL;
Cet index garantit qu'une seule ligne avec
ended_at IS NULLpeut exister parantenna_id. Même en cas de requêtes concurrentes atteignant simultanément la base, PostgreSQL rejette la seconde insertion avec uneIntegrityError. C'est le filet de sécurité ultime, indépendant du code applicatif.SELECT ... FOR UPDATE(défense au niveau applicatif) : Avant chaque insertion, le service verrouille la ligne de l'éventuelle intervention active existante. Cela sérialise les transactions concurrentes et renvoie une erreur métier explicite (409 Conflict) avant même d'atteindre la contrainte SQL.
Cette combinaison couvre à la fois la concurrence au niveau applicatif (lock pessimiste) et les cas extrêmes de race condition au niveau base (contrainte unique partielle).