9.2 KiB
✅ 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,handlerspour utiliserRespondWithAppErroretRespondSuccess - ✅ Helper
respondWithError()créé (lignes 113-127) : Convertit HTTP status → ErrorCode → RespondWithAppError - ✅ Helper
getUserID()mis à jour : Utilise maintenantRespondWithAppErrorau lieu deresponse.Unauthorized - ✅ Endpoints critiques migrés :
UploadTrack:response.BadRequest→h.respondWithError(),response.Created→handlers.RespondSuccess()GetUploadStatus:response.BadRequest,response.InternalServerError,response.Success→ format standardiséUpdateTrack:response.BadRequest,response.NotFound,response.Forbidden,response.InternalServerError,response.Success→ format standardisé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é :
{
"success": false,
"error": {
"code": 2000,
"message": "invalid track id",
"timestamp": "2025-12-12T19:00:00Z",
"request_id": "...",
"details": []
}
}
Helper créé
// 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) :
response.BadRequest(c, "invalid track id")
// → {"success": false, "error": "invalid track id"}
Après (format structuré) :
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
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
TestTrackHandler_ErrorResponseFormat
- ✅ Vérifie que les erreurs suivent le format
RespondWithAppError - ✅ Vérifie la présence des champs :
code,message,timestamp - ✅ Vérifie que
codeest un nombre positif - ✅ Vérifie que
messageest une string non vide - ✅ Vérifie que
timestampest au format RFC3339
Test 2 : Format des réponses de succès
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
successesttrue
Tests complets
go test ./internal/core/track -v -count=1
Résultat : ✅ Tous les tests passent
📊 COMPARAISON DES PATTERNS
Pattern internal/response (ancien)
Format :
{
"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 :
{
"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
go build ./internal/core/track/...
Résultat : ✅ Compilation réussie
Tests unitaires
go test ./internal/core/track -run TestTrackHandler_ErrorResponseFormat -v
Résultat : ✅ Tests passent
Tests complets
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
go build ./internal/core/track/...
Tests spécifiques
go test ./internal/core/track -run TestTrackHandler_ErrorResponseFormat -v -count=1
go test ./internal/core/track -run TestTrackHandler_SuccessResponseFormat -v -count=1
Tests complets
go test ./internal/core/track -v -count=1
📝 ENDPOINTS DÉSORMAIS COHÉRENTS
Les endpoints suivants utilisent maintenant le format standardisé RespondWithAppError / RespondSuccess :
- ✅
POST /tracks(UploadTrack) - Endpoint très exposé - ✅
GET /tracks/:id/progress(GetUploadStatus) - Utilisé fréquemment - ✅
PUT /tracks/:id(UpdateTrack) - Modification critique - ✅
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.