generated from gilles/template-webapp
import ali
This commit is contained in:
+157
-12
@@ -1,24 +1,169 @@
|
||||
# Contrat d’erreurs API
|
||||
# Contrat d'erreurs API
|
||||
|
||||
Ce document définit le format standard des erreurs.
|
||||
Ce document définit le format standard des erreurs de l'API HomeStock.
|
||||
|
||||
---
|
||||
|
||||
## Légende des zones
|
||||
- `<A COMPLETER PAR AGENT>` : à compléter par un agent spécialisé backend.
|
||||
## 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 -->
|
||||
|
||||
---
|
||||
|
||||
## Format
|
||||
- Structure : <A COMPLETER PAR AGENT>
|
||||
- Codes d’erreur : <A COMPLETER PAR AGENT>
|
||||
- Messages utilisateurs vs techniques : <A COMPLETER PAR AGENT>
|
||||
## 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
|
||||
- Codes HTTP : <A COMPLETER PAR AGENT>
|
||||
- Champs obligatoires : <A COMPLETER PAR AGENT>
|
||||
|
||||
### 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 -->
|
||||
|
||||
---
|
||||
|
||||
## Exemple (a supprimer)
|
||||
- `{ "error": { "code": "VALIDATION_ERROR", "message": "Email invalide" } }`
|
||||
## 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 -->
|
||||
|
||||
Reference in New Issue
Block a user