go 62 lines · 8 steps

Partial-success responses in Gin

A Gin handler that accepts imperfect input, records non-fatal warnings, and reports them with 207 Multi-Status.

Explained by highlit
1type Warning struct {
2 Field string `json:"field"`
3 Code string `json:"code"`
4 Message string `json:"message"`
5}
6 
7type Envelope struct {
8 Data interface{} `json:"data"`
9 Warnings []Warning `json:"warnings,omitempty"`
10}
11 
12func (h *Handler) ImportContact(c *gin.Context) {
13 var req ContactInput
14 if err := c.ShouldBindJSON(&req); err != nil {
15 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
16 return
17 }
18 
19 warnings := make([]Warning, 0, 3)
20 
21 if normalized, ok := normalizePhone(req.Phone); ok {
22 req.Phone = normalized
23 } else if req.Phone != "" {
24 warnings = append(warnings, Warning{
25 Field: "phone",
26 Code: "unparseable",
27 Message: "phone number could not be normalized and was stored as-is",
28 })
29 }
30 
31 if !validEmail(req.Email) {
32 warnings = append(warnings, Warning{
33 Field: "email",
34 Code: "unverified",
35 Message: "email failed MX lookup; delivery is not guaranteed",
36 })
37 }
38 
39 if req.CompanyID != 0 {
40 if _, err := h.companies.Get(c.Request.Context(), req.CompanyID); err != nil {
41 req.CompanyID = 0
42 warnings = append(warnings, Warning{
43 Field: "company_id",
44 Code: "not_found",
45 Message: "referenced company does not exist and was cleared",
46 })
47 }
48 }
49 
50 contact, err := h.contacts.Create(c.Request.Context(), req)
51 if err != nil {
52 c.JSON(http.StatusInternalServerError, gin.H{"error": "could not save contact"})
53 return
54 }
55 
56 status := http.StatusCreated
57 if len(warnings) > 0 {
58 status = http.StatusMultiStatus
59 }
60 
61 c.JSON(status, Envelope{Data: contact, Warnings: warnings})
62}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Distinguishing fatal errors from recoverable warnings lets an API accept messy input without silently dropping data.
  2. 2A response envelope with an optional warnings array communicates what was corrected alongside the created resource.
  3. 3HTTP 207 Multi-Status is the honest signal for a request that succeeded with caveats.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Partial-success responses in Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code