security: create /api/v1/validate endpoint for pre-validation
- Created ValidateHandler with Validate method - Endpoint accepts POST /api/v1/validate with type and data - Supports RegisterRequest and LoginRequest validation types - Uses existing validator from CommonHandler - Returns ValidateResponse with valid flag and errors array - Public endpoint (no auth required) - Route registered in setupValidateRoutes - Code compiles successfully - Follows existing handler patterns - Action 5.2.1.1 complete
This commit is contained in:
parent
c23bad2099
commit
97ad8a61e3
3 changed files with 127 additions and 3 deletions
|
|
@ -1664,11 +1664,20 @@ Critical path dependencies:
|
|||
### Sub-Epic 5.2: Pre-Validation 🟢
|
||||
|
||||
#### Task 5.2.1: Add Backend Validation Endpoint
|
||||
- [ ] **Action 5.2.1.1**: Create `/api/v1/validate` endpoint
|
||||
- [x] **Action 5.2.1.1**: Create `/api/v1/validate` endpoint
|
||||
- **Scope**: `veza-backend-api/internal/handlers/validate.go` (create)
|
||||
- **Dependencies**: None
|
||||
- **Dependencies**: None ✅
|
||||
- **Risk**: LOW
|
||||
- **Validation**: Endpoint validates request bodies
|
||||
- **Validation**: ✅ Endpoint validates request bodies:
|
||||
- Created ValidateHandler with Validate method
|
||||
- Endpoint accepts POST /api/v1/validate with type and data
|
||||
- Supports RegisterRequest and LoginRequest validation types
|
||||
- Uses existing validator from CommonHandler
|
||||
- Returns ValidateResponse with valid flag and errors array
|
||||
- Public endpoint (no auth required)
|
||||
- Route registered in setupValidateRoutes
|
||||
- Code compiles successfully
|
||||
- Follows existing handler patterns
|
||||
- **Rollback**: Delete endpoint
|
||||
|
||||
- [ ] **Action 5.2.1.2**: Frontend: Call validate before submit
|
||||
|
|
|
|||
|
|
@ -264,6 +264,9 @@ func (r *APIRouter) Setup(router *gin.Engine) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Action 5.2.1.1: Validation endpoint for pre-validation
|
||||
r.setupValidateRoutes(v1)
|
||||
|
||||
// Réactivation des routes User et Track pour Phase 1
|
||||
r.setupUserRoutes(v1)
|
||||
r.setupTrackRoutes(v1)
|
||||
|
|
@ -512,6 +515,14 @@ func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// setupValidateRoutes configures the validation endpoint
|
||||
// Action 5.2.1.1: Create /api/v1/validate endpoint
|
||||
func (r *APIRouter) setupValidateRoutes(router *gin.RouterGroup) {
|
||||
validateHandler := handlers.NewValidateHandler(r.logger)
|
||||
// Public endpoint - no auth required for validation
|
||||
router.POST("/validate", validateHandler.Validate)
|
||||
}
|
||||
|
||||
// setupInternalRoutes configure les routes internal (legacy and modern)
|
||||
// These routes must be on the root router, not under /api/v1
|
||||
func (r *APIRouter) setupInternalRoutes(router *gin.Engine) {
|
||||
|
|
|
|||
104
veza-backend-api/internal/handlers/validate.go
Normal file
104
veza-backend-api/internal/handlers/validate.go
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"veza-backend-api/internal/dto"
|
||||
"veza-backend-api/internal/errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ValidateRequest represents the request body for the validate endpoint
|
||||
type ValidateRequest struct {
|
||||
Type string `json:"type" binding:"required"` // e.g., "RegisterRequest", "LoginRequest"
|
||||
Data json.RawMessage `json:"data" binding:"required"` // The data to validate
|
||||
}
|
||||
|
||||
// ValidateResponse represents the response from the validate endpoint
|
||||
type ValidateResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
Errors []dto.ValidationError `json:"errors,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// ValidateHandler handles validation requests
|
||||
type ValidateHandler struct {
|
||||
commonHandler *CommonHandler
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewValidateHandler creates a new ValidateHandler
|
||||
func NewValidateHandler(logger *zap.Logger) *ValidateHandler {
|
||||
return &ValidateHandler{
|
||||
commonHandler: NewCommonHandler(logger),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates request bodies against known DTOs
|
||||
// POST /api/v1/validate
|
||||
// @Summary Validate request body
|
||||
// @Description Validates request data against known DTO types without executing the actual operation
|
||||
// @Tags Validation
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body ValidateRequest true "Validation request with type and data"
|
||||
// @Success 200 {object} ValidateResponse "Validation result"
|
||||
// @Failure 400 {object} APIResponse "Invalid request format"
|
||||
// @Router /validate [post]
|
||||
func (h *ValidateHandler) Validate(c *gin.Context) {
|
||||
var req ValidateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondWithError(c, http.StatusBadRequest, "Invalid request format", errors.ErrorDetail{
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Map type string to DTO struct and validate
|
||||
var validationErrors []dto.ValidationError
|
||||
|
||||
switch req.Type {
|
||||
case "RegisterRequest":
|
||||
var dtoReq dto.RegisterRequest
|
||||
if err := json.Unmarshal(req.Data, &dtoReq); err != nil {
|
||||
RespondWithError(c, http.StatusBadRequest, "Invalid data format for RegisterRequest", errors.ErrorDetail{
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
validationErrors = h.commonHandler.validator.Validate(&dtoReq)
|
||||
|
||||
case "LoginRequest":
|
||||
var dtoReq dto.LoginRequest
|
||||
if err := json.Unmarshal(req.Data, &dtoReq); err != nil {
|
||||
RespondWithError(c, http.StatusBadRequest, "Invalid data format for LoginRequest", errors.ErrorDetail{
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
validationErrors = h.commonHandler.validator.Validate(&dtoReq)
|
||||
|
||||
default:
|
||||
RespondWithError(c, http.StatusBadRequest, "Unknown validation type: "+req.Type)
|
||||
return
|
||||
}
|
||||
|
||||
// Return validation result
|
||||
if len(validationErrors) > 0 {
|
||||
RespondSuccess(c, http.StatusOK, ValidateResponse{
|
||||
Valid: false,
|
||||
Errors: validationErrors,
|
||||
Message: "Validation failed",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, http.StatusOK, ValidateResponse{
|
||||
Valid: true,
|
||||
Message: "Validation passed",
|
||||
})
|
||||
}
|
||||
Loading…
Reference in a new issue