Files
home_stock/contracts/errors.md
2026-02-01 01:45:51 +01:00

170 lines
5.4 KiB
Markdown

# Contrat d'erreurs API
Ce document définit le format standard des erreurs de l'API HomeStock.
---
## Format des réponses d'erreur
### Erreurs métier (HTTPException)
Toutes les erreurs métier utilisent `fastapi.HTTPException` et retournent :
```json
{
"detail": "Message d'erreur lisible"
}
```
<!-- complété par codex -->
### Erreurs de validation (Pydantic / FastAPI)
Les erreurs de validation des paramètres ou du corps de requête retournent automatiquement :
```json
{
"detail": [
{
"type": "validation_error",
"loc": ["body", "name"],
"msg": "String should have at least 1 character",
"input": ""
}
]
}
```
<!-- complété par codex -->
### Erreurs internes (500)
Le gestionnaire global (`main.py`) retourne :
```json
{
"detail": "Message technique (dev) ou 'Erreur interne du serveur' (prod)",
"type": "internal_server_error"
}
```
En développement, le message contient les détails de l'exception.
En production, le message est masqué pour la sécurité.
<!-- complété par codex -->
---
## Codes HTTP utilisés
| Code | Signification | Usage |
|------|---------------|-------|
| **200** | OK | GET, PUT, PATCH réussis |
| **201** | Created | POST réussi (création de ressource) |
| **204** | No Content | DELETE réussi (documents) |
| **400** | Bad Request | Données invalides (type de fichier, taille, auto-référence) |
| **404** | Not Found | Ressource inexistante (item, catégorie, emplacement, boutique, document, fichier physique) |
| **409** | Conflict | Conflit d'unicité (nom dupliqué, n° de série) ou dépendance empêchant la suppression |
| **422** | Unprocessable Entity | Erreur de validation Pydantic (format automatique FastAPI) |
| **500** | Internal Server Error | Exception non gérée |
<!-- complété par codex -->
---
## Codes d'erreur par domaine
### Items (`/api/v1/items`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 404 | Item non trouvé | `Objet {id} non trouvé` |
| 404 | Catégorie référencée inexistante | `Catégorie {id} non trouvée` |
| 404 | Emplacement référencé inexistant | `Emplacement {id} non trouvé` |
| 409 | N° de série déjà utilisé | `Un objet avec le numéro de série '{sn}' existe déjà` |
### Catégories (`/api/v1/categories`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 404 | Catégorie non trouvée | `Catégorie {id} non trouvée` |
| 409 | Nom déjà utilisé | `Une catégorie avec le nom '{name}' existe déjà` |
| 409 | Suppression avec items liés | `Impossible de supprimer : {n} objet(s) utilisent cette catégorie` |
### Emplacements (`/api/v1/locations`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 404 | Emplacement non trouvé | `Emplacement {id} non trouvé` |
| 404 | Parent inexistant | `Emplacement parent {id} non trouvé` |
| 400 | Auto-référence | `Un emplacement ne peut pas être son propre parent` |
| 409 | Suppression avec items liés | `Impossible de supprimer : {n} objet(s) utilisent cet emplacement` |
| 409 | Suppression avec sous-emplacements | `Impossible de supprimer : cet emplacement a {n} sous-emplacement(s)` |
### Boutiques (`/api/v1/shops`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 404 | Boutique non trouvée | `Boutique {id} non trouvée` |
| 409 | Nom déjà utilisé | `Une boutique avec le nom '{name}' existe déjà` |
| 409 | Suppression avec items liés | `Impossible de supprimer : {n} objet(s) sont associés à cette boutique` |
### Documents (`/api/v1/documents`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 404 | Item parent inexistant | `Item {id} non trouvé` |
| 404 | Document non trouvé | `Document non trouvé` |
| 404 | Fichier physique manquant | `Fichier non trouvé sur le disque` |
| 400 | Type MIME non autorisé | `Type de fichier non autorisé : {mime}. Types acceptés : images (JPEG, PNG, GIF, WebP) et PDF` |
| 400 | Photo sans image | `Le type 'photo' nécessite un fichier image` |
| 400 | Fichier trop volumineux | `Fichier trop volumineux ({size} Mo). Taille max : 10 Mo` |
### Import CSV (`/api/v1/import`)
| Code HTTP | Situation | Message |
|-----------|-----------|---------|
| 400 | Fichier non CSV | `Le fichier doit être un CSV (.csv)` |
| 400 | Indices de sélection invalides | `Format d'indices invalide` |
| 400 | Statut d'item invalide | `Statut invalide : {status}` |
<!-- complété par codex -->
---
## Conventions
### Champs obligatoires
Toute réponse d'erreur contient au minimum le champ `detail` (string ou array).
<!-- complété par codex -->
### Messages
- Les messages sont en **français**, destinés à l'utilisateur final
- Ils incluent le contexte nécessaire (ID de la ressource, nom dupliqué, taille du fichier)
- En production (500), le message technique est masqué
### Gestion côté client
Le frontend intercepte les erreurs via un intercepteur Axios (`api/client.ts`) qui log l'erreur dans la console. Le champ `detail` est affiché à l'utilisateur.
<!-- complété par codex -->
---
## Schéma de réponse (schemas/common.py)
```python
class ErrorResponse(BaseModel):
detail: str # Message d'erreur
type: str # Type d'erreur (ex: "internal_server_error")
class SuccessResponse(BaseModel):
message: str # Message de succès
id: int | None # ID de l'élément concerné
```
<!-- complété par codex -->