go 40 lines · 8 steps

Structured validation errors in Gin

A Gin handler validates a nested JSON payload with binding tags and returns per-field errors when it fails.

Explained by highlit
1package handler
2 
3type LineItem struct {
4 SKU string `json:"sku" binding:"required,alphanum"`
5 Quantity int `json:"quantity" binding:"required,gt=0,lte=100"`
6 UnitCost float64 `json:"unit_cost" binding:"required,gt=0"`
7}
8 
9type CreateOrderRequest struct {
10 CustomerID string `json:"customer_id" binding:"required,uuid"`
11 Currency string `json:"currency" binding:"required,iso4217"`
12 Items []LineItem `json:"items" binding:"required,min=1,max=50,dive"`
13}
14 
15func CreateOrder(orders *OrderService) gin.HandlerFunc {
16 return func(c *gin.Context) {
17 var req CreateOrderRequest
18 if err := c.ShouldBindJSON(&req); err != nil {
19 var verrs validator.ValidationErrors
20 if errors.As(err, &verrs) {
21 fields := make(map[string]string, len(verrs))
22 for _, fe := range verrs {
23 fields[fe.Namespace()] = fe.Tag()
24 }
25 c.JSON(http.StatusUnprocessableEntity, gin.H{"errors": fields})
26 return
27 }
28 c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
29 return
30 }
31 
32 order, err := orders.Create(c.Request.Context(), req.CustomerID, req.Currency, req.Items)
33 if err != nil {
34 c.JSON(http.StatusInternalServerError, gin.H{"error": "could not create order"})
35 return
36 }
37 
38 c.JSON(http.StatusCreated, order)
39 }
40}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Struct tags let you declare validation rules declaratively instead of writing manual checks.
  2. 2Distinguishing validation errors from other bind failures gives clients actionable, field-level feedback.
  3. 3Returning a closure over a service keeps handlers testable and free of global state.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Structured validation errors in Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code