286 lines
9.2 KiB
Markdown
286 lines
9.2 KiB
Markdown
|
|
# ✅ P1-RES-001 — STANDARDISATION PATTERNS DE RÉPONSE D'ERREUR
|
||
|
|
|
||
|
|
**Date**: 2025-12-12
|
||
|
|
**Objectif**: Standardiser les patterns de réponse d'erreur en migrant TrackHandler vers `RespondWithAppError`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 RÉSUMÉ
|
||
|
|
|
||
|
|
✅ **Pattern cible identifié** : `RespondWithAppError` (conforme ORIGIN_API_SPECIFICATION)
|
||
|
|
✅ **Helper créé** : `respondWithError()` pour faciliter la migration
|
||
|
|
✅ **Endpoints critiques migrés** : UploadTrack, GetUploadStatus, UpdateTrack, DeleteTrack
|
||
|
|
✅ **Tests ajoutés** : Vérification de la forme des erreurs (structure JSON)
|
||
|
|
✅ **Compilation réussie** : Aucune erreur de compilation
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📁 FICHIERS MODIFIÉS
|
||
|
|
|
||
|
|
### 1. `internal/core/track/handler.go`
|
||
|
|
- ✅ **Imports ajoutés** : `apperrors`, `handlers` pour utiliser `RespondWithAppError` et `RespondSuccess`
|
||
|
|
- ✅ **Helper `respondWithError()` créé** (lignes 113-127) : Convertit HTTP status → ErrorCode → RespondWithAppError
|
||
|
|
- ✅ **Helper `getUserID()` mis à jour** : Utilise maintenant `RespondWithAppError` au lieu de `response.Unauthorized`
|
||
|
|
- ✅ **Endpoints critiques migrés** :
|
||
|
|
1. `UploadTrack` : `response.BadRequest` → `h.respondWithError()`, `response.Created` → `handlers.RespondSuccess()`
|
||
|
|
2. `GetUploadStatus` : `response.BadRequest`, `response.InternalServerError`, `response.Success` → format standardisé
|
||
|
|
3. `UpdateTrack` : `response.BadRequest`, `response.NotFound`, `response.Forbidden`, `response.InternalServerError`, `response.Success` → format standardisé
|
||
|
|
4. `DeleteTrack` : `response.BadRequest`, `response.NotFound`, `response.Forbidden`, `response.InternalServerError`, `response.Success` → format standardisé
|
||
|
|
|
||
|
|
### 2. `internal/core/track/handler_error_format_test.go` (nouveau)
|
||
|
|
- ✅ `TestTrackHandler_ErrorResponseFormat` : Teste la structure JSON des erreurs (code, message, timestamp)
|
||
|
|
- ✅ `TestTrackHandler_SuccessResponseFormat` : Teste la structure JSON des réponses de succès
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔍 IMPLÉMENTATION
|
||
|
|
|
||
|
|
### Pattern cible : `RespondWithAppError`
|
||
|
|
|
||
|
|
**Format standardisé** :
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": false,
|
||
|
|
"error": {
|
||
|
|
"code": 2000,
|
||
|
|
"message": "invalid track id",
|
||
|
|
"timestamp": "2025-12-12T19:00:00Z",
|
||
|
|
"request_id": "...",
|
||
|
|
"details": []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Helper créé
|
||
|
|
|
||
|
|
```go
|
||
|
|
// respondWithError est un helper pour migrer vers RespondWithAppError
|
||
|
|
// MOD-P1-RES-001: Helper pour standardiser les réponses d'erreur
|
||
|
|
func (h *TrackHandler) respondWithError(c *gin.Context, httpStatus int, message string) {
|
||
|
|
var errCode apperrors.ErrorCode
|
||
|
|
switch httpStatus {
|
||
|
|
case http.StatusBadRequest:
|
||
|
|
errCode = apperrors.ErrCodeValidation
|
||
|
|
case http.StatusUnauthorized:
|
||
|
|
errCode = apperrors.ErrCodeUnauthorized
|
||
|
|
case http.StatusForbidden:
|
||
|
|
errCode = apperrors.ErrCodeForbidden
|
||
|
|
case http.StatusNotFound:
|
||
|
|
errCode = apperrors.ErrCodeNotFound
|
||
|
|
case http.StatusInternalServerError:
|
||
|
|
errCode = apperrors.ErrCodeInternal
|
||
|
|
default:
|
||
|
|
errCode = apperrors.ErrCodeInternal
|
||
|
|
}
|
||
|
|
handlers.RespondWithAppError(c, apperrors.New(errCode, message))
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Pattern de remplacement
|
||
|
|
|
||
|
|
**Avant** (format simple) :
|
||
|
|
```go
|
||
|
|
response.BadRequest(c, "invalid track id")
|
||
|
|
// → {"success": false, "error": "invalid track id"}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Après** (format structuré) :
|
||
|
|
```go
|
||
|
|
h.respondWithError(c, http.StatusBadRequest, "invalid track id")
|
||
|
|
// → {"success": false, "error": {"code": 2000, "message": "invalid track id", "timestamp": "...", ...}}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 MATRICE AVANT/APRÈS
|
||
|
|
|
||
|
|
| Endpoint | Méthode | Avant (Pattern) | Après (Pattern) | Status HTTP | Format erreur |
|
||
|
|
|----------|---------|----------------|-----------------|------------|---------------|
|
||
|
|
| `POST /tracks` | UploadTrack | `response.BadRequest()` | `h.respondWithError()` | 400 | ✅ Structuré |
|
||
|
|
| `POST /tracks` | UploadTrack | `response.Created()` | `handlers.RespondSuccess()` | 201 | ✅ Standardisé |
|
||
|
|
| `GET /tracks/:id/progress` | GetUploadStatus | `response.BadRequest()` | `h.respondWithError()` | 400 | ✅ Structuré |
|
||
|
|
| `GET /tracks/:id/progress` | GetUploadStatus | `response.Success()` | `handlers.RespondSuccess()` | 200 | ✅ Standardisé |
|
||
|
|
| `PUT /tracks/:id` | UpdateTrack | `response.BadRequest()` | `h.respondWithError()` | 400 | ✅ Structuré |
|
||
|
|
| `PUT /tracks/:id` | UpdateTrack | `response.NotFound()` | `h.respondWithError()` | 404 | ✅ Structuré |
|
||
|
|
| `PUT /tracks/:id` | UpdateTrack | `response.Forbidden()` | `h.respondWithError()` | 403 | ✅ Structuré |
|
||
|
|
| `PUT /tracks/:id` | UpdateTrack | `response.Success()` | `handlers.RespondSuccess()` | 200 | ✅ Standardisé |
|
||
|
|
| `DELETE /tracks/:id` | DeleteTrack | `response.BadRequest()` | `h.respondWithError()` | 400 | ✅ Structuré |
|
||
|
|
| `DELETE /tracks/:id` | DeleteTrack | `response.NotFound()` | `h.respondWithError()` | 404 | ✅ Structuré |
|
||
|
|
| `DELETE /tracks/:id` | DeleteTrack | `response.Forbidden()` | `h.respondWithError()` | 403 | ✅ Structuré |
|
||
|
|
| `DELETE /tracks/:id` | DeleteTrack | `response.Success()` | `handlers.RespondSuccess()` | 200 | ✅ Standardisé |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🧪 PREUVES (TESTS)
|
||
|
|
|
||
|
|
### Tests unitaires
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -run TestTrackHandler_ErrorResponseFormat -v -count=1
|
||
|
|
```
|
||
|
|
|
||
|
|
**Résultat** : ✅ **Tests passent** (vérification de la structure JSON)
|
||
|
|
|
||
|
|
#### Test 1 : Format des erreurs
|
||
|
|
```go
|
||
|
|
TestTrackHandler_ErrorResponseFormat
|
||
|
|
```
|
||
|
|
- ✅ Vérifie que les erreurs suivent le format `RespondWithAppError`
|
||
|
|
- ✅ Vérifie la présence des champs : `code`, `message`, `timestamp`
|
||
|
|
- ✅ Vérifie que `code` est un nombre positif
|
||
|
|
- ✅ Vérifie que `message` est une string non vide
|
||
|
|
- ✅ Vérifie que `timestamp` est au format RFC3339
|
||
|
|
|
||
|
|
#### Test 2 : Format des réponses de succès
|
||
|
|
```go
|
||
|
|
TestTrackHandler_SuccessResponseFormat
|
||
|
|
```
|
||
|
|
- ✅ Vérifie que les réponses de succès suivent le format `RespondSuccess`
|
||
|
|
- ✅ Vérifie la présence des champs : `success`, `data`
|
||
|
|
- ✅ Vérifie que `success` est `true`
|
||
|
|
|
||
|
|
### Tests complets
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -v -count=1
|
||
|
|
```
|
||
|
|
|
||
|
|
**Résultat** : ✅ **Tous les tests passent**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 COMPARAISON DES PATTERNS
|
||
|
|
|
||
|
|
### Pattern `internal/response` (ancien)
|
||
|
|
|
||
|
|
**Format** :
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": false,
|
||
|
|
"error": "invalid track id"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Avantages** :
|
||
|
|
- Simple et direct
|
||
|
|
- Facile à utiliser
|
||
|
|
|
||
|
|
**Inconvénients** :
|
||
|
|
- Pas de code d'erreur standardisé
|
||
|
|
- Pas de timestamp
|
||
|
|
- Pas de détails structurés
|
||
|
|
- Incohérent avec ProfileHandler
|
||
|
|
|
||
|
|
### Pattern `RespondWithAppError` (nouveau)
|
||
|
|
|
||
|
|
**Format** :
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": false,
|
||
|
|
"error": {
|
||
|
|
"code": 2000,
|
||
|
|
"message": "invalid track id",
|
||
|
|
"timestamp": "2025-12-12T19:00:00Z",
|
||
|
|
"request_id": "...",
|
||
|
|
"details": []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Avantages** :
|
||
|
|
- ✅ Format structuré et standardisé
|
||
|
|
- ✅ Code d'erreur pour traitement programmatique
|
||
|
|
- ✅ Timestamp pour debugging
|
||
|
|
- ✅ Request ID pour traçabilité
|
||
|
|
- ✅ Détails pour erreurs de validation
|
||
|
|
- ✅ Cohérent avec ProfileHandler et autres handlers
|
||
|
|
- ✅ Conforme à ORIGIN_API_SPECIFICATION
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ VALIDATION
|
||
|
|
|
||
|
|
### Compilation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go build ./internal/core/track/...
|
||
|
|
```
|
||
|
|
|
||
|
|
**Résultat** : ✅ **Compilation réussie**
|
||
|
|
|
||
|
|
### Tests unitaires
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -run TestTrackHandler_ErrorResponseFormat -v
|
||
|
|
```
|
||
|
|
|
||
|
|
**Résultat** : ✅ **Tests passent**
|
||
|
|
|
||
|
|
### Tests complets
|
||
|
|
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -v -count=1
|
||
|
|
```
|
||
|
|
|
||
|
|
**Résultat** : ✅ **Tous les tests passent**
|
||
|
|
|
||
|
|
### Vérification cohérence
|
||
|
|
|
||
|
|
Les endpoints suivants utilisent maintenant le **même format** que ProfileHandler :
|
||
|
|
- ✅ `POST /tracks` (UploadTrack)
|
||
|
|
- ✅ `GET /tracks/:id/progress` (GetUploadStatus)
|
||
|
|
- ✅ `PUT /tracks/:id` (UpdateTrack)
|
||
|
|
- ✅ `DELETE /tracks/:id` (DeleteTrack)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 OBJECTIFS ATTEINTS
|
||
|
|
|
||
|
|
- ✅ **Pattern cible identifié** : `RespondWithAppError` (conforme ORIGIN_API_SPECIFICATION)
|
||
|
|
- ✅ **Endpoints critiques migrés** : 4 endpoints les plus exposés
|
||
|
|
- ✅ **Helper créé** : `respondWithError()` pour faciliter la migration
|
||
|
|
- ✅ **Tests ajoutés** : Vérification de la structure JSON des erreurs
|
||
|
|
- ✅ **Cohérence améliorée** : TrackHandler et ProfileHandler utilisent maintenant le même format
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 COMMANDES DE VALIDATION
|
||
|
|
|
||
|
|
### Compilation
|
||
|
|
```bash
|
||
|
|
go build ./internal/core/track/...
|
||
|
|
```
|
||
|
|
|
||
|
|
### Tests spécifiques
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -run TestTrackHandler_ErrorResponseFormat -v -count=1
|
||
|
|
go test ./internal/core/track -run TestTrackHandler_SuccessResponseFormat -v -count=1
|
||
|
|
```
|
||
|
|
|
||
|
|
### Tests complets
|
||
|
|
```bash
|
||
|
|
go test ./internal/core/track -v -count=1
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📝 ENDPOINTS DÉSORMAIS COHÉRENTS
|
||
|
|
|
||
|
|
Les endpoints suivants utilisent maintenant le **format standardisé** `RespondWithAppError` / `RespondSuccess` :
|
||
|
|
|
||
|
|
1. ✅ **`POST /tracks`** (UploadTrack) - Endpoint très exposé
|
||
|
|
2. ✅ **`GET /tracks/:id/progress`** (GetUploadStatus) - Utilisé fréquemment
|
||
|
|
3. ✅ **`PUT /tracks/:id`** (UpdateTrack) - Modification critique
|
||
|
|
4. ✅ **`DELETE /tracks/:id`** (DeleteTrack) - Suppression critique
|
||
|
|
|
||
|
|
Ces endpoints sont maintenant **cohérents** avec :
|
||
|
|
- ✅ `ProfileHandler` (GetProfile, UpdateProfile, etc.)
|
||
|
|
- ✅ `PlaylistHandler` (utilise déjà `RespondWithAppError`)
|
||
|
|
- ✅ `AuthHandler` (utilise déjà `RespondWithAppError`)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Statut final** : ✅ **P1-RES-001 IMPLÉMENTÉ ET VALIDÉ**
|
||
|
|
|
||
|
|
**Note** : La migration complète de tous les endpoints TrackHandler vers `RespondWithAppError` peut être effectuée progressivement. Les 4 endpoints critiques ont été migrés pour supprimer l'incohérence observable côté clients.
|