diff --git a/context.go b/context.go index c724daf344..209ca2e19d 100644 --- a/context.go +++ b/context.go @@ -87,9 +87,18 @@ type Context struct { // or PUT body parameters. formCache url.Values - // SameSite allows a server to define a cookie attribute making it impossible for + // sameSite allows a server to define a cookie attribute making it impossible for // the browser to send this cookie along with cross-site requests. sameSite http.SameSite + + // jsonRender the JSON renderer currently used. The default value is render.JSON, + // which is used to get the JSON rendering type when executing the c.JSON function. + jsonRender func(data any) render.Render +} + +// SetJSONRender set the current JSON render +func (c *Context) SetJSONRender(jsonRender func(data any) render.Render) { + c.jsonRender = jsonRender } /************************************/ @@ -109,6 +118,8 @@ func (c *Context) reset() { c.queryCache = nil c.formCache = nil c.sameSite = 0 + // registering a default JSON renderer + c.jsonRender = render.NewJSON *c.params = (*c.params)[:0] *c.skippedNodes = (*c.skippedNodes)[:0] } @@ -1095,7 +1106,7 @@ func (c *Context) JSONP(code int, obj any) { // JSON serializes the given struct as JSON into the response body. // It also sets the Content-Type as "application/json". func (c *Context) JSON(code int, obj any) { - c.Render(code, render.JSON{Data: obj}) + c.Render(code, c.jsonRender(obj)) } // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. diff --git a/context_test.go b/context_test.go index 5b63a647c9..6adddc4724 100644 --- a/context_test.go +++ b/context_test.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "github.com/gin-gonic/gin/render" "html/template" "io" "io/fs" @@ -166,7 +167,7 @@ func TestSaveUploadedFileWithPermission(t *testing.T) { require.NoError(t, err) mw.Close() c, _ := CreateTestContext(httptest.NewRecorder()) - c.Request, _ = http.NewRequest("POST", "/", buf) + c.Request, _ = http.NewRequest(http.MethodPost,, "/", buf) c.Request.Header.Set("Content-Type", mw.FormDataContentType()) f, err := c.FormFile("file") require.NoError(t, err) @@ -187,7 +188,7 @@ func TestSaveUploadedFileWithPermissionFailed(t *testing.T) { require.NoError(t, err) mw.Close() c, _ := CreateTestContext(httptest.NewRecorder()) - c.Request, _ = http.NewRequest("POST", "/", buf) + c.Request, _ = http.NewRequest(http.MethodPost, "/", buf) c.Request.Header.Set("Content-Type", mw.FormDataContentType()) f, err := c.FormFile("file") require.NoError(t, err) @@ -3123,3 +3124,31 @@ func TestContextNext(t *testing.T) { assert.True(t, exists) assert.Equal(t, "value3", value) } + +// MyJSON customizing JSON rendering +type MyJSON struct { + Data any + render.JSON +} + +// Render rewrite the Render function +func (r MyJSON) Render(w http.ResponseWriter) error { + _, err := w.Write([]byte("test")) + return err +} + +func NewMyJSON(data any) render.Render { + return &MyJSON{Data: data} +} + +// TestCustomJSONRender the test uses a custom JSON render. +// The final result is that the user can customize the JSON render without affecting the original function. +func TestCustomJSONRender(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + c.SetJSONRender(NewMyJSON) + + c.JSON(http.StatusCreated, H{"foo": "bar", "html": ""}) + + t.Log(w.Body.String()) +} diff --git a/render/json.go b/render/json.go index fc8dea453f..80e0a9eb7c 100644 --- a/render/json.go +++ b/render/json.go @@ -19,6 +19,10 @@ type JSON struct { Data any } +func NewJSON(data any) Render { + return &JSON{Data: data} +} + // IndentedJSON contains the given interface object. type IndentedJSON struct { Data any