mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
return err instead of panic in JSON Render
This commit is contained in:
parent
580e7da6ee
commit
4cfab1be20
86
context.go
86
context.go
@ -195,9 +195,9 @@ func (c *Context) AbortWithStatus(code int) {
|
||||
// AbortWithStatusJSON calls `Abort()` and then `JSON` internally.
|
||||
// This method stops the chain, writes the status code and return a JSON body.
|
||||
// It also sets the Content-Type as "application/json".
|
||||
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) {
|
||||
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{}) error {
|
||||
c.Abort()
|
||||
c.JSON(code, jsonObj)
|
||||
return c.JSON(code, jsonObj)
|
||||
}
|
||||
|
||||
// AbortWithError calls `AbortWithStatus()` and `Error()` internally.
|
||||
@ -884,97 +884,94 @@ func (c *Context) Cookie(name string) (string, error) {
|
||||
}
|
||||
|
||||
// Render writes the response headers and calls render.Render to render data.
|
||||
func (c *Context) Render(code int, r render.Render) {
|
||||
func (c *Context) Render(code int, r render.Render) error {
|
||||
c.Status(code)
|
||||
|
||||
if !bodyAllowedForStatus(code) {
|
||||
r.WriteContentType(c.Writer)
|
||||
c.Writer.WriteHeaderNow()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := r.Render(c.Writer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return r.Render(c.Writer)
|
||||
}
|
||||
|
||||
// HTML renders the HTTP template specified by its file name.
|
||||
// It also updates the HTTP code and sets the Content-Type as "text/html".
|
||||
// See http://golang.org/doc/articles/wiki/
|
||||
func (c *Context) HTML(code int, name string, obj interface{}) {
|
||||
func (c *Context) HTML(code int, name string, obj interface{}) error {
|
||||
instance := c.engine.HTMLRender.Instance(name, obj)
|
||||
c.Render(code, instance)
|
||||
return c.Render(code, instance)
|
||||
}
|
||||
|
||||
// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
|
||||
// It also sets the Content-Type as "application/json".
|
||||
// WARNING: we recommend using this only for development purposes since printing pretty JSON is
|
||||
// more CPU and bandwidth consuming. Use Context.JSON() instead.
|
||||
func (c *Context) IndentedJSON(code int, obj interface{}) {
|
||||
c.Render(code, render.IndentedJSON{Data: obj})
|
||||
func (c *Context) IndentedJSON(code int, obj interface{}) error {
|
||||
return c.Render(code, render.IndentedJSON{Data: obj})
|
||||
}
|
||||
|
||||
// SecureJSON serializes the given struct as Secure JSON into the response body.
|
||||
// Default prepends "while(1)," to response body if the given struct is array values.
|
||||
// It also sets the Content-Type as "application/json".
|
||||
func (c *Context) SecureJSON(code int, obj interface{}) {
|
||||
c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
|
||||
func (c *Context) SecureJSON(code int, obj interface{}) error {
|
||||
return c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
|
||||
}
|
||||
|
||||
// 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".
|
||||
func (c *Context) JSONP(code int, obj interface{}) {
|
||||
func (c *Context) JSONP(code int, obj interface{}) error {
|
||||
callback := c.DefaultQuery("callback", "")
|
||||
if callback == "" {
|
||||
c.Render(code, render.JSON{Data: obj})
|
||||
return
|
||||
return c.Render(code, render.JSON{Data: obj})
|
||||
}
|
||||
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
|
||||
return c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
|
||||
}
|
||||
|
||||
// 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 interface{}) {
|
||||
c.Render(code, render.JSON{Data: obj})
|
||||
func (c *Context) JSON(code int, obj interface{}) error {
|
||||
return c.Render(code, render.JSON{Data: obj})
|
||||
}
|
||||
|
||||
// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
|
||||
// It also sets the Content-Type as "application/json".
|
||||
func (c *Context) AsciiJSON(code int, obj interface{}) {
|
||||
c.Render(code, render.AsciiJSON{Data: obj})
|
||||
func (c *Context) AsciiJSON(code int, obj interface{}) error {
|
||||
return c.Render(code, render.AsciiJSON{Data: obj})
|
||||
}
|
||||
|
||||
// PureJSON serializes the given struct as JSON into the response body.
|
||||
// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
|
||||
func (c *Context) PureJSON(code int, obj interface{}) {
|
||||
c.Render(code, render.PureJSON{Data: obj})
|
||||
func (c *Context) PureJSON(code int, obj interface{}) error {
|
||||
return c.Render(code, render.PureJSON{Data: obj})
|
||||
}
|
||||
|
||||
// XML serializes the given struct as XML into the response body.
|
||||
// It also sets the Content-Type as "application/xml".
|
||||
func (c *Context) XML(code int, obj interface{}) {
|
||||
c.Render(code, render.XML{Data: obj})
|
||||
func (c *Context) XML(code int, obj interface{}) error {
|
||||
return c.Render(code, render.XML{Data: obj})
|
||||
}
|
||||
|
||||
// YAML serializes the given struct as YAML into the response body.
|
||||
func (c *Context) YAML(code int, obj interface{}) {
|
||||
c.Render(code, render.YAML{Data: obj})
|
||||
func (c *Context) YAML(code int, obj interface{}) error {
|
||||
return c.Render(code, render.YAML{Data: obj})
|
||||
}
|
||||
|
||||
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
|
||||
func (c *Context) ProtoBuf(code int, obj interface{}) {
|
||||
c.Render(code, render.ProtoBuf{Data: obj})
|
||||
func (c *Context) ProtoBuf(code int, obj interface{}) error {
|
||||
return c.Render(code, render.ProtoBuf{Data: obj})
|
||||
}
|
||||
|
||||
// String writes the given string into the response body.
|
||||
func (c *Context) String(code int, format string, values ...interface{}) {
|
||||
c.Render(code, render.String{Format: format, Data: values})
|
||||
func (c *Context) String(code int, format string, values ...interface{}) error {
|
||||
return c.Render(code, render.String{Format: format, Data: values})
|
||||
}
|
||||
|
||||
// Redirect returns an HTTP redirect to the specific location.
|
||||
func (c *Context) Redirect(code int, location string) {
|
||||
c.Render(-1, render.Redirect{
|
||||
func (c *Context) Redirect(code int, location string) error {
|
||||
return c.Render(-1, render.Redirect{
|
||||
Code: code,
|
||||
Location: location,
|
||||
Request: c.Request,
|
||||
@ -982,16 +979,16 @@ func (c *Context) Redirect(code int, location string) {
|
||||
}
|
||||
|
||||
// Data writes some data into the body stream and updates the HTTP code.
|
||||
func (c *Context) Data(code int, contentType string, data []byte) {
|
||||
c.Render(code, render.Data{
|
||||
func (c *Context) Data(code int, contentType string, data []byte) error {
|
||||
return c.Render(code, render.Data{
|
||||
ContentType: contentType,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// DataFromReader writes the specified reader into the body stream and updates the HTTP code.
|
||||
func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) {
|
||||
c.Render(code, render.Reader{
|
||||
func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) error {
|
||||
return c.Render(code, render.Reader{
|
||||
Headers: extraHeaders,
|
||||
ContentType: contentType,
|
||||
ContentLength: contentLength,
|
||||
@ -1023,8 +1020,8 @@ func (c *Context) FileAttachment(filepath, filename string) {
|
||||
}
|
||||
|
||||
// SSEvent writes a Server-Sent Event into the body stream.
|
||||
func (c *Context) SSEvent(name string, message interface{}) {
|
||||
c.Render(-1, sse.Event{
|
||||
func (c *Context) SSEvent(name string, message interface{}) error {
|
||||
return c.Render(-1, sse.Event{
|
||||
Event: name,
|
||||
Data: message,
|
||||
})
|
||||
@ -1065,26 +1062,27 @@ type Negotiate struct {
|
||||
}
|
||||
|
||||
// Negotiate calls different Render according to acceptable Accept format.
|
||||
func (c *Context) Negotiate(code int, config Negotiate) {
|
||||
func (c *Context) Negotiate(code int, config Negotiate) error {
|
||||
switch c.NegotiateFormat(config.Offered...) {
|
||||
case binding.MIMEJSON:
|
||||
data := chooseData(config.JSONData, config.Data)
|
||||
c.JSON(code, data)
|
||||
return c.JSON(code, data)
|
||||
|
||||
case binding.MIMEHTML:
|
||||
data := chooseData(config.HTMLData, config.Data)
|
||||
c.HTML(code, config.HTMLName, data)
|
||||
return c.HTML(code, config.HTMLName, data)
|
||||
|
||||
case binding.MIMEXML:
|
||||
data := chooseData(config.XMLData, config.Data)
|
||||
c.XML(code, data)
|
||||
return c.XML(code, data)
|
||||
|
||||
case binding.MIMEYAML:
|
||||
data := chooseData(config.YAMLData, config.Data)
|
||||
c.YAML(code, data)
|
||||
return c.YAML(code, data)
|
||||
|
||||
default:
|
||||
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) // nolint: errcheck
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
116
context_test.go
116
context_test.go
@ -642,25 +642,18 @@ func TestContextBodyAllowedForStatus(t *testing.T) {
|
||||
assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
type TestPanicRender struct{}
|
||||
type TestErrorRender struct{}
|
||||
|
||||
func (*TestPanicRender) Render(http.ResponseWriter) error {
|
||||
return errors.New("TestPanicRender")
|
||||
func (*TestErrorRender) Render(http.ResponseWriter) error {
|
||||
return errors.New("TestErrorRender")
|
||||
}
|
||||
|
||||
func (*TestPanicRender) WriteContentType(http.ResponseWriter) {}
|
||||
func (*TestErrorRender) WriteContentType(http.ResponseWriter) {}
|
||||
|
||||
func TestContextRenderPanicIfErr(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
assert.Equal(t, "TestPanicRender", fmt.Sprint(r))
|
||||
}()
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Render(http.StatusOK, &TestPanicRender{})
|
||||
|
||||
assert.Fail(t, "Panic not detected")
|
||||
assert.Error(t, c.Render(http.StatusOK, &TestErrorRender{}))
|
||||
}
|
||||
|
||||
// Tests that the response is serialized as JSON
|
||||
@ -670,7 +663,7 @@ func TestContextRenderJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.JSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
|
||||
assert.NoError(t, c.JSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
|
||||
@ -684,7 +677,7 @@ func TestContextRenderJSONP(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "http://example.com/?callback=x", nil)
|
||||
|
||||
c.JSONP(http.StatusCreated, H{"foo": "bar"})
|
||||
assert.NoError(t, c.JSONP(http.StatusCreated, H{"foo": "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "x({\"foo\":\"bar\"});", w.Body.String())
|
||||
@ -698,7 +691,7 @@ func TestContextRenderJSONPWithoutCallback(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("GET", "http://example.com", nil)
|
||||
|
||||
c.JSONP(http.StatusCreated, H{"foo": "bar"})
|
||||
assert.NoError(t, c.JSONP(http.StatusCreated, H{"foo": "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
||||
@ -750,8 +743,7 @@ func TestContextRenderIndentedJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
|
||||
|
||||
assert.NoError(t, c.IndentedJSON(http.StatusCreated, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}))
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String())
|
||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
@ -762,7 +754,7 @@ func TestContextRenderNoContentIndentedJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
|
||||
assert.NoError(t, c.IndentedJSON(http.StatusNoContent, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -776,7 +768,7 @@ func TestContextRenderSecureJSON(t *testing.T) {
|
||||
c, router := CreateTestContext(w)
|
||||
|
||||
router.SecureJsonPrefix("&&&START&&&")
|
||||
c.SecureJSON(http.StatusCreated, []string{"foo", "bar"})
|
||||
assert.NoError(t, c.SecureJSON(http.StatusCreated, []string{"foo", "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String())
|
||||
@ -788,7 +780,7 @@ func TestContextRenderNoContentSecureJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"})
|
||||
assert.NoError(t, c.SecureJSON(http.StatusNoContent, []string{"foo", "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -799,7 +791,7 @@ func TestContextRenderNoContentAsciiJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.AsciiJSON(http.StatusNoContent, []string{"lang", "Go语言"})
|
||||
assert.NoError(t, c.AsciiJSON(http.StatusNoContent, []string{"lang", "Go语言"}))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -812,7 +804,7 @@ func TestContextRenderNoContentAsciiJSON(t *testing.T) {
|
||||
func TestContextRenderPureJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"})
|
||||
assert.NoError(t, c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": "<b>"}))
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
|
||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
@ -827,7 +819,7 @@ func TestContextRenderHTML(t *testing.T) {
|
||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||
router.SetHTMLTemplate(templ)
|
||||
|
||||
c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})
|
||||
assert.NoError(t, c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "Hello alexandernyquist", w.Body.String())
|
||||
@ -851,7 +843,7 @@ func TestContextRenderHTML2(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", re)
|
||||
|
||||
c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"})
|
||||
assert.NoError(t, c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "Hello alexandernyquist", w.Body.String())
|
||||
@ -865,7 +857,7 @@ func TestContextRenderNoContentHTML(t *testing.T) {
|
||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||
router.SetHTMLTemplate(templ)
|
||||
|
||||
c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"})
|
||||
assert.NoError(t, c.HTML(http.StatusNoContent, "t", H{"name": "alexandernyquist"}))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -878,7 +870,7 @@ func TestContextRenderXML(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.XML(http.StatusCreated, H{"foo": "bar"})
|
||||
assert.NoError(t, c.XML(http.StatusCreated, H{"foo": "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
|
||||
@ -890,7 +882,7 @@ func TestContextRenderNoContentXML(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.XML(http.StatusNoContent, H{"foo": "bar"})
|
||||
assert.NoError(t, c.XML(http.StatusNoContent, H{"foo": "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -903,7 +895,7 @@ func TestContextRenderString(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.String(http.StatusCreated, "test %s %d", "string", 2)
|
||||
assert.NoError(t, c.String(http.StatusCreated, "test %s %d", "string", 2))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "test string 2", w.Body.String())
|
||||
@ -915,7 +907,7 @@ func TestContextRenderNoContentString(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.String(http.StatusNoContent, "test %s %d", "string", 2)
|
||||
assert.NoError(t, c.String(http.StatusNoContent, "test %s %d", "string", 2))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -929,7 +921,7 @@ func TestContextRenderHTMLString(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3)
|
||||
assert.NoError(t, c.String(http.StatusCreated, "<html>%s %d</html>", "string", 3))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "<html>string 3</html>", w.Body.String())
|
||||
@ -942,7 +934,7 @@ func TestContextRenderNoContentHTMLString(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3)
|
||||
assert.NoError(t, c.String(http.StatusNoContent, "<html>%s %d</html>", "string", 3))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -955,7 +947,7 @@ func TestContextRenderData(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`))
|
||||
assert.NoError(t, c.Data(http.StatusCreated, "text/csv", []byte(`foo,bar`)))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "foo,bar", w.Body.String())
|
||||
@ -967,7 +959,7 @@ func TestContextRenderNoContentData(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`))
|
||||
assert.NoError(t, c.Data(http.StatusNoContent, "text/csv", []byte(`foo,bar`)))
|
||||
|
||||
assert.Equal(t, http.StatusNoContent, w.Code)
|
||||
assert.Empty(t, w.Body.String())
|
||||
@ -978,15 +970,15 @@ func TestContextRenderSSE(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.SSEvent("float", 1.5)
|
||||
c.Render(-1, sse.Event{
|
||||
assert.NoError(t, c.SSEvent("float", 1.5))
|
||||
assert.NoError(t, c.Render(-1, sse.Event{
|
||||
Id: "123",
|
||||
Data: "text",
|
||||
})
|
||||
c.SSEvent("chat", H{
|
||||
}))
|
||||
assert.NoError(t, c.SSEvent("chat", H{
|
||||
"foo": "bar",
|
||||
"bar": "foo",
|
||||
})
|
||||
}))
|
||||
|
||||
assert.Equal(t, strings.Replace(w.Body.String(), " ", "", -1), strings.Replace("event:float\ndata:1.5\n\nid:123\ndata:text\n\nevent:chat\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n", " ", "", -1))
|
||||
}
|
||||
@ -1039,7 +1031,7 @@ func TestContextRenderYAML(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.YAML(http.StatusCreated, H{"foo": "bar"})
|
||||
assert.NoError(t, c.YAML(http.StatusCreated, H{"foo": "bar"}))
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
assert.Equal(t, "foo: bar\n", w.Body.String())
|
||||
@ -1060,7 +1052,7 @@ func TestContextRenderProtoBuf(t *testing.T) {
|
||||
Reps: reps,
|
||||
}
|
||||
|
||||
c.ProtoBuf(http.StatusCreated, data)
|
||||
assert.NoError(t, c.ProtoBuf(http.StatusCreated, data))
|
||||
|
||||
protoData, err := proto.Marshal(data)
|
||||
assert.NoError(t, err)
|
||||
@ -1092,10 +1084,10 @@ func TestContextRenderRedirectWithRelativePath(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
|
||||
assert.Panics(t, func() { c.Redirect(299, "/new_path") })
|
||||
assert.Panics(t, func() { c.Redirect(309, "/new_path") })
|
||||
assert.Error(t, c.Redirect(299, "/new_path"))
|
||||
assert.Error(t, c.Redirect(309, "/new_path"))
|
||||
|
||||
c.Redirect(http.StatusMovedPermanently, "/path")
|
||||
assert.NoError(t, c.Redirect(http.StatusMovedPermanently, "/path"))
|
||||
c.Writer.WriteHeaderNow()
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||
@ -1106,7 +1098,7 @@ func TestContextRenderRedirectWithAbsolutePath(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
|
||||
c.Redirect(http.StatusFound, "http://google.com")
|
||||
assert.NoError(t, c.Redirect(http.StatusFound, "http://google.com"))
|
||||
c.Writer.WriteHeaderNow()
|
||||
|
||||
assert.Equal(t, http.StatusFound, w.Code)
|
||||
@ -1118,7 +1110,7 @@ func TestContextRenderRedirectWith201(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
|
||||
c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
|
||||
c.Redirect(http.StatusCreated, "/resource")
|
||||
assert.NoError(t, c.Redirect(http.StatusCreated, "/resource"))
|
||||
c.Writer.WriteHeaderNow()
|
||||
|
||||
assert.Equal(t, http.StatusCreated, w.Code)
|
||||
@ -1128,12 +1120,12 @@ func TestContextRenderRedirectWith201(t *testing.T) {
|
||||
func TestContextRenderRedirectAll(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
|
||||
assert.Panics(t, func() { c.Redirect(http.StatusOK, "/resource") })
|
||||
assert.Panics(t, func() { c.Redirect(http.StatusAccepted, "/resource") })
|
||||
assert.Panics(t, func() { c.Redirect(299, "/resource") })
|
||||
assert.Panics(t, func() { c.Redirect(309, "/resource") })
|
||||
assert.NotPanics(t, func() { c.Redirect(http.StatusMultipleChoices, "/resource") })
|
||||
assert.NotPanics(t, func() { c.Redirect(http.StatusPermanentRedirect, "/resource") })
|
||||
assert.Error(t, c.Redirect(http.StatusOK, "/resource"))
|
||||
assert.Error(t, c.Redirect(http.StatusAccepted, "/resource"))
|
||||
assert.Error(t, c.Redirect(299, "/resource"))
|
||||
assert.Error(t, c.Redirect(309, "/resource"))
|
||||
assert.NoError(t, c.Redirect(http.StatusMultipleChoices, "/resource"))
|
||||
assert.NoError(t, c.Redirect(http.StatusPermanentRedirect, "/resource"))
|
||||
}
|
||||
|
||||
func TestContextNegotiationWithJSON(t *testing.T) {
|
||||
@ -1141,10 +1133,10 @@ func TestContextNegotiationWithJSON(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||
|
||||
c.Negotiate(http.StatusOK, Negotiate{
|
||||
assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{
|
||||
Offered: []string{MIMEJSON, MIMEXML, MIMEYAML},
|
||||
Data: H{"foo": "bar"},
|
||||
})
|
||||
}))
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
||||
@ -1156,10 +1148,10 @@ func TestContextNegotiationWithXML(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||
|
||||
c.Negotiate(http.StatusOK, Negotiate{
|
||||
assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{
|
||||
Offered: []string{MIMEXML, MIMEJSON, MIMEYAML},
|
||||
Data: H{"foo": "bar"},
|
||||
})
|
||||
}))
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
|
||||
@ -1173,11 +1165,11 @@ func TestContextNegotiationWithHTML(t *testing.T) {
|
||||
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
|
||||
router.SetHTMLTemplate(templ)
|
||||
|
||||
c.Negotiate(http.StatusOK, Negotiate{
|
||||
assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{
|
||||
Offered: []string{MIMEHTML},
|
||||
Data: H{"name": "gin"},
|
||||
HTMLName: "t",
|
||||
})
|
||||
}))
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "Hello gin", w.Body.String())
|
||||
@ -1189,9 +1181,9 @@ func TestContextNegotiationNotSupport(t *testing.T) {
|
||||
c, _ := CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||
|
||||
c.Negotiate(http.StatusOK, Negotiate{
|
||||
assert.NoError(t, c.Negotiate(http.StatusOK, Negotiate{
|
||||
Offered: []string{MIMEPOSTForm},
|
||||
})
|
||||
}))
|
||||
|
||||
assert.Equal(t, http.StatusNotAcceptable, w.Code)
|
||||
assert.Equal(t, c.index, abortIndex)
|
||||
@ -1297,7 +1289,7 @@ func TestContextAbortWithStatusJSON(t *testing.T) {
|
||||
in.Bar = "barValue"
|
||||
in.Foo = "fooValue"
|
||||
|
||||
c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in)
|
||||
assert.NoError(t, c.AbortWithStatusJSON(http.StatusUnsupportedMediaType, in))
|
||||
|
||||
assert.Equal(t, abortIndex, c.index)
|
||||
assert.Equal(t, http.StatusUnsupportedMediaType, c.Writer.Status())
|
||||
@ -1925,7 +1917,7 @@ func TestContextRenderDataFromReader(t *testing.T) {
|
||||
contentType := "image/png"
|
||||
extraHeaders := map[string]string{"Content-Disposition": `attachment; filename="gopher.png"`}
|
||||
|
||||
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
|
||||
assert.NoError(t, c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders))
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, body, w.Body.String())
|
||||
@ -1943,7 +1935,7 @@ func TestContextRenderDataFromReaderNoHeaders(t *testing.T) {
|
||||
contentLength := int64(len(body))
|
||||
contentType := "image/png"
|
||||
|
||||
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil)
|
||||
assert.NoError(t, c.DataFromReader(http.StatusOK, contentLength, contentType, reader, nil))
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, body, w.Body.String())
|
||||
|
@ -54,10 +54,7 @@ var (
|
||||
|
||||
// Render (JSON) writes data with custom ContentType.
|
||||
func (r JSON) Render(w http.ResponseWriter) (err error) {
|
||||
if err = WriteJSON(w, r.Data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
return WriteJSON(w, r.Data)
|
||||
}
|
||||
|
||||
// WriteContentType (JSON) writes JSON ContentType.
|
||||
|
@ -19,7 +19,7 @@ type Redirect struct {
|
||||
// Render (Redirect) redirects the http request to new location and writes redirect response.
|
||||
func (r Redirect) Render(w http.ResponseWriter) error {
|
||||
if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated {
|
||||
panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
|
||||
return fmt.Errorf("Cannot redirect with status code %d", r.Code)
|
||||
}
|
||||
http.Redirect(w, r.Request, r.Location, r.Code)
|
||||
return nil
|
||||
|
@ -39,12 +39,12 @@ func TestRenderJSON(t *testing.T) {
|
||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
}
|
||||
|
||||
func TestRenderJSONPanics(t *testing.T) {
|
||||
func TestRenderJSONError(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
data := make(chan int)
|
||||
|
||||
// json: unsupported type: chan int
|
||||
assert.Panics(t, func() { assert.NoError(t, (JSON{data}).Render(w)) })
|
||||
assert.Error(t, (JSON{data}).Render(w))
|
||||
}
|
||||
|
||||
func TestRenderIndentedJSON(t *testing.T) {
|
||||
@ -320,10 +320,7 @@ func TestRenderRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
assert.PanicsWithValue(t, "Cannot redirect with status code 200", func() {
|
||||
err := data2.Render(w)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
assert.EqualError(t, data2.Render(w), "Cannot redirect with status code 200")
|
||||
|
||||
data3 := Redirect{
|
||||
Code: http.StatusCreated,
|
||||
|
Loading…
x
Reference in New Issue
Block a user