diff --git a/context.go b/context.go index 112f0ee0..bd177642 100644 --- a/context.go +++ b/context.go @@ -1173,13 +1173,10 @@ func (c *Context) SecureJSON(code int, obj any) { // JSONP serializes the given struct as JSON into the response body. // It adds padding to response body to request data from a server residing in a different domain than the client. // It also sets the Content-Type as "application/javascript". +// +// When the callback parameter is empty, it behaves equivalently to Context.JSON. func (c *Context) JSONP(code int, obj any) { - callback := c.DefaultQuery("callback", "") - if callback == "" { - c.Render(code, render.JSON{Data: obj}) - return - } - c.Render(code, render.JsonpJSON{Callback: callback, Data: obj}) + c.Render(code, render.JsonpJSON{Callback: c.Query("callback"), Data: obj}) } // JSON serializes the given struct as JSON into the response body. diff --git a/render/json.go b/render/json.go index 2f98676c..ceeeca9c 100644 --- a/render/json.go +++ b/render/json.go @@ -115,14 +115,14 @@ func (r SecureJSON) WriteContentType(w http.ResponseWriter) { // Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType. func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { - r.WriteContentType(w) - ret, err := json.API.Marshal(r.Data) - if err != nil { - return err + if r.Callback == "" { + return WriteJSON(w, r.Data) } - if r.Callback == "" { - _, err = w.Write(ret) + r.WriteContentType(w) + + ret, err := json.API.Marshal(r.Data) + if err != nil { return err } diff --git a/render/render_test.go b/render/render_test.go index d9ae2067..180b0b0c 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -183,19 +183,28 @@ func TestRenderJsonpJSONError(t *testing.T) { assert.Equal(t, `write "`+`);`+`" error`, err.Error()) } -func TestRenderJsonpJSONError2(t *testing.T) { +func TestRenderJsonpJSONWithEmptyCallback(t *testing.T) { w := httptest.NewRecorder() data := map[string]any{ "foo": "bar", + "num": 42, + "nested": map[string]any{ + "key": "value", + }, } - (JsonpJSON{"", data}).WriteContentType(w) - assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) - e := (JsonpJSON{"", data}).Render(w) - require.NoError(t, e) + err := (JsonpJSON{Callback: "", Data: data}).Render(w) - assert.JSONEq(t, "{\"foo\":\"bar\"}", w.Body.String()) - assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) + require.NoError(t, err) + + // Verify Content-Type is set to jsonContentType when callback is empty + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) + + renderData, err := json.API.Marshal(data) + require.NoError(t, err) + + // Verify body contains correct JSON data + assert.JSONEq(t, string(renderData), w.Body.String()) } func TestRenderJsonpJSONFail(t *testing.T) {