From 18ac5c0cc57a32b63ffe5ed354395a1a2607bb73 Mon Sep 17 00:00:00 2001 From: Viktar Tairau Date: Tue, 5 May 2026 22:05:08 +0300 Subject: [PATCH] Return defaults for non 2** statuses responses --- handler.go | 2 +- handler_test.go | 95 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/handler.go b/handler.go index 152b791..27b4353 100644 --- a/handler.go +++ b/handler.go @@ -30,7 +30,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { resp := rec.Result() if !IsSuccess(resp) || !IsJSON(resp) { - h.write(w, resp) + h.write(w, NewJsonResponse(http.StatusOK, resp.Header, route.Default)) return } diff --git a/handler_test.go b/handler_test.go index f65f570..49887c1 100644 --- a/handler_test.go +++ b/handler_test.go @@ -57,10 +57,13 @@ func TestHandler_RouteNotMatched_PassesThrough(t *testing.T) { assert.Equal(t, "ok", rr.Body.String()) } -func TestHandler_Not2xx_PassesThrough(t *testing.T) { +func TestHandler_Not2xx_JSON_ReturnsDefaults(t *testing.T) { cfg := &Config{ Routes: []Route{ - {Path: "/products/{product}/positions"}, + { + Path: "/products/{product}/positions", + Default: map[string]interface{}{"positions": []interface{}{}}, + }, }, } @@ -69,14 +72,90 @@ func TestHandler_Not2xx_PassesThrough(t *testing.T) { rr := doRequest(t, h, "GET", "/products/iphonex64s/positions") - assert.Equal(t, http.StatusInternalServerError, rr.Code) - assert.Equal(t, `{"error":"boom"}`, rr.Body.String()) + assert.Equal(t, http.StatusOK, rr.Code) + + out := decodeJSON(t, rr.Body.Bytes()) + assert.Equal(t, []interface{}{}, out["positions"]) + _, hasError := out["error"] + assert.False(t, hasError) } -func TestHandler_NotJSON_PassesThrough(t *testing.T) { +func TestHandler_401_JSON_ReturnsDefaults(t *testing.T) { cfg := &Config{ Routes: []Route{ - {Path: "/products/{product}/positions"}, + { + Path: "/products/{product}/positions", + Default: map[string]interface{}{"positions": []interface{}{}, "shops": nil}, + }, + }, + } + + next := newNext(401, "application/json", `{"error":"unauthorized"}`) + h := NewHandler(cfg, next, noopLogger{}) + + rr := doRequest(t, h, "GET", "/products/iphonex64s/positions") + + assert.Equal(t, http.StatusOK, rr.Code) + + out := decodeJSON(t, rr.Body.Bytes()) + _, ok := out["positions"] + assert.True(t, ok) + _, ok = out["shops"] + assert.True(t, ok) + _, hasError := out["error"] + assert.False(t, hasError) +} + +func TestHandler_403_JSON_ReturnsDefaults(t *testing.T) { + cfg := &Config{ + Routes: []Route{ + { + Path: "/products/{product}/positions", + Default: map[string]interface{}{"positions": []interface{}{}, "extra": "default_val"}, + }, + }, + } + + next := newNext(403, "application/json", `{"error":"forbidden","positions":[1,2]}`) + h := NewHandler(cfg, next, noopLogger{}) + + rr := doRequest(t, h, "GET", "/products/iphonex64s/positions") + + assert.Equal(t, http.StatusOK, rr.Code) + + out := decodeJSON(t, rr.Body.Bytes()) + assert.Equal(t, []interface{}{}, out["positions"]) + assert.Equal(t, "default_val", out["extra"]) +} + +func TestHandler_Not2xx_NotJSON_ReturnsDefaults(t *testing.T) { + cfg := &Config{ + Routes: []Route{ + { + Path: "/products/{product}/positions", + Default: map[string]interface{}{"positions": []interface{}{}}, + }, + }, + } + + next := newNext(500, "text/plain", "internal error") + h := NewHandler(cfg, next, noopLogger{}) + + rr := doRequest(t, h, "GET", "/products/iphonex64s/positions") + + assert.Equal(t, http.StatusOK, rr.Code) + + out := decodeJSON(t, rr.Body.Bytes()) + assert.Equal(t, []interface{}{}, out["positions"]) +} + +func TestHandler_NotJSON_ReturnsDefaults(t *testing.T) { + cfg := &Config{ + Routes: []Route{ + { + Path: "/products/{product}/positions", + Default: map[string]interface{}{"positions": []interface{}{}}, + }, }, } @@ -86,7 +165,9 @@ func TestHandler_NotJSON_PassesThrough(t *testing.T) { rr := doRequest(t, h, "GET", "/products/iphonex64s/positions") assert.Equal(t, http.StatusOK, rr.Code) - assert.Equal(t, "hello", rr.Body.String()) + + out := decodeJSON(t, rr.Body.Bytes()) + assert.Equal(t, []interface{}{}, out["positions"]) } func TestHandler_JSONSuccess_AddsDefaults(t *testing.T) {