Merge 4a1434ad5e5d05845e6331caa25a240f45c04e9f into d5b353c5d5a560322e6d96121c814115562501f7

This commit is contained in:
David Martorana 2017-06-19 16:54:37 +00:00 committed by GitHub
commit 9fbe44d98f
3 changed files with 45 additions and 39 deletions

View File

@ -422,47 +422,43 @@ func (c *Context) Cookie(name string) (string, error) {
return val, nil return val, nil
} }
func (c *Context) Render(code int, r render.Render) { func (c *Context) Render(code int, r render.Render) error {
c.Status(code) c.Status(code)
if err := r.Render(c.Writer); err != nil { return r.Render(c.Writer)
panic(err)
}
} }
// HTML renders the HTTP template specified by its file name. // HTML renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html". // It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/ // 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) 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. // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development propuses since printing pretty JSON is // WARNING: we recommend to use this only for development propuses since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead. // more CPU and bandwidth consuming. Use Context.JSON() instead.
func (c *Context) IndentedJSON(code int, obj interface{}) { func (c *Context) IndentedJSON(code int, obj interface{}) error {
c.Render(code, render.IndentedJSON{Data: obj}) return c.Render(code, render.IndentedJSON{Data: obj})
} }
// JSON serializes the given struct as JSON into the response body. // JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) { func (c *Context) JSON(code int, obj interface{}) error {
c.Status(code) c.Status(code)
if err := render.WriteJSON(c.Writer, obj); err != nil { return render.WriteJSON(c.Writer, obj)
panic(err)
}
} }
// XML serializes the given struct as XML into the response body. // XML serializes the given struct as XML into the response body.
// It also sets the Content-Type as "application/xml". // It also sets the Content-Type as "application/xml".
func (c *Context) XML(code int, obj interface{}) { func (c *Context) XML(code int, obj interface{}) error {
c.Render(code, render.XML{Data: obj}) return c.Render(code, render.XML{Data: obj})
} }
// YAML serializes the given struct as YAML into the response body. // YAML serializes the given struct as YAML into the response body.
func (c *Context) YAML(code int, obj interface{}) { func (c *Context) YAML(code int, obj interface{}) error {
c.Render(code, render.YAML{Data: obj}) return c.Render(code, render.YAML{Data: obj})
} }
// String writes the given string into the response body. // String writes the given string into the response body.
@ -472,8 +468,8 @@ func (c *Context) String(code int, format string, values ...interface{}) {
} }
// Redirect returns a HTTP redirect to the specific location. // Redirect returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) { func (c *Context) Redirect(code int, location string) error {
c.Render(-1, render.Redirect{ return c.Render(-1, render.Redirect{
Code: code, Code: code,
Location: location, Location: location,
Request: c.Request, Request: c.Request,
@ -481,8 +477,8 @@ func (c *Context) Redirect(code int, location string) {
} }
// Data writes some data into the body stream and updates the HTTP code. // Data writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte) { func (c *Context) Data(code int, contentType string, data []byte) error {
c.Render(code, render.Data{ return c.Render(code, render.Data{
ContentType: contentType, ContentType: contentType,
Data: data, Data: data,
}) })
@ -494,8 +490,8 @@ func (c *Context) File(filepath string) {
} }
// SSEvent writes a Server-Sent Event into the body stream. // SSEvent writes a Server-Sent Event into the body stream.
func (c *Context) SSEvent(name string, message interface{}) { func (c *Context) SSEvent(name string, message interface{}) error {
c.Render(-1, sse.Event{ return c.Render(-1, sse.Event{
Event: name, Event: name,
Data: message, Data: message,
}) })

View File

@ -351,8 +351,9 @@ func TestContextGetCookie(t *testing.T) {
// and Content-Type is set to application/json // and Content-Type is set to application/json
func TestContextRenderJSON(t *testing.T) { func TestContextRenderJSON(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.JSON(201, H{"foo": "bar"}) e := c.JSON(201, H{"foo": "bar"})
assert.NoError(t, e)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "{\"foo\":\"bar\"}\n") assert.Equal(t, w.Body.String(), "{\"foo\":\"bar\"}\n")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
@ -363,8 +364,9 @@ func TestContextRenderJSON(t *testing.T) {
func TestContextRenderAPIJSON(t *testing.T) { func TestContextRenderAPIJSON(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.Header("Content-Type", "application/vnd.api+json") c.Header("Content-Type", "application/vnd.api+json")
c.JSON(201, H{"foo": "bar"}) e := c.JSON(201, H{"foo": "bar"})
assert.NoError(t, e)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "{\"foo\":\"bar\"}\n") assert.Equal(t, w.Body.String(), "{\"foo\":\"bar\"}\n")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json")
@ -374,8 +376,9 @@ func TestContextRenderAPIJSON(t *testing.T) {
// and Content-Type is set to application/json // and Content-Type is set to application/json
func TestContextRenderIndentedJSON(t *testing.T) { func TestContextRenderIndentedJSON(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.IndentedJSON(201, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}}) err := c.IndentedJSON(201, H{"foo": "bar", "bar": "foo", "nested": H{"foo": "bar"}})
assert.NoError(t, err)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}") assert.Equal(t, w.Body.String(), "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/json; charset=utf-8")
@ -388,8 +391,9 @@ func TestContextRenderHTML(t *testing.T) {
templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) templ := template.Must(template.New("t").Parse(`Hello {{.name}}`))
router.SetHTMLTemplate(templ) router.SetHTMLTemplate(templ)
c.HTML(201, "t", H{"name": "alexandernyquist"}) err := c.HTML(201, "t", H{"name": "alexandernyquist"})
assert.NoError(t, err)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "Hello alexandernyquist") assert.Equal(t, w.Body.String(), "Hello alexandernyquist")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/html; charset=utf-8") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/html; charset=utf-8")
@ -399,8 +403,9 @@ func TestContextRenderHTML(t *testing.T) {
// and Content-Type is set to application/xml // and Content-Type is set to application/xml
func TestContextRenderXML(t *testing.T) { func TestContextRenderXML(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.XML(201, H{"foo": "bar"}) err := c.XML(201, H{"foo": "bar"})
assert.NoError(t, err)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "<map><foo>bar</foo></map>") assert.Equal(t, w.Body.String(), "<map><foo>bar</foo></map>")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/xml; charset=utf-8") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/xml; charset=utf-8")
@ -433,8 +438,9 @@ func TestContextRenderHTMLString(t *testing.T) {
// with specified MIME type // with specified MIME type
func TestContextRenderData(t *testing.T) { func TestContextRenderData(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.Data(201, "text/csv", []byte(`foo,bar`)) err := c.Data(201, "text/csv", []byte(`foo,bar`))
assert.NoError(t, err)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "foo,bar") assert.Equal(t, w.Body.String(), "foo,bar")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/csv") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "text/csv")
@ -469,8 +475,9 @@ func TestContextRenderFile(t *testing.T) {
// and Content-Type is set to application/x-yaml // and Content-Type is set to application/x-yaml
func TestContextRenderYAML(t *testing.T) { func TestContextRenderYAML(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.YAML(201, H{"foo": "bar"}) err := c.YAML(201, H{"foo": "bar"})
assert.NoError(t, err)
assert.Equal(t, w.Code, 201) assert.Equal(t, w.Code, 201)
assert.Equal(t, w.Body.String(), "foo: bar\n") assert.Equal(t, w.Body.String(), "foo: bar\n")
assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/x-yaml; charset=utf-8") assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/x-yaml; charset=utf-8")
@ -496,10 +503,12 @@ func TestContextHeaders(t *testing.T) {
func TestContextRenderRedirectWithRelativePath(t *testing.T) { func TestContextRenderRedirectWithRelativePath(t *testing.T) {
c, w, _ := CreateTestContext() c, w, _ := CreateTestContext()
c.Request, _ = http.NewRequest("POST", "http://example.com", nil) c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
assert.Panics(t, func() { c.Redirect(299, "/new_path") }) assert.Error(t, c.Redirect(299, "/new_path"))
assert.Panics(t, func() { c.Redirect(309, "/new_path") }) assert.Error(t, c.Redirect(309, "/new_path"))
err := c.Redirect(301, "/path")
assert.NoError(t, err)
c.Redirect(301, "/path")
c.Writer.WriteHeaderNow() c.Writer.WriteHeaderNow()
assert.Equal(t, w.Code, 301) assert.Equal(t, w.Code, 301)
assert.Equal(t, w.Header().Get("Location"), "/path") assert.Equal(t, w.Header().Get("Location"), "/path")
@ -528,12 +537,12 @@ func TestContextRenderRedirectWith201(t *testing.T) {
func TestContextRenderRedirectAll(t *testing.T) { func TestContextRenderRedirectAll(t *testing.T) {
c, _, _ := CreateTestContext() c, _, _ := CreateTestContext()
c.Request, _ = http.NewRequest("POST", "http://example.com", nil) c.Request, _ = http.NewRequest("POST", "http://example.com", nil)
assert.Panics(t, func() { c.Redirect(200, "/resource") }) assert.Error(t, c.Redirect(200, "/resource"))
assert.Panics(t, func() { c.Redirect(202, "/resource") }) assert.Error(t, c.Redirect(202, "/resource"))
assert.Panics(t, func() { c.Redirect(299, "/resource") }) assert.Error(t, c.Redirect(299, "/resource"))
assert.Panics(t, func() { c.Redirect(309, "/resource") }) assert.Error(t, c.Redirect(309, "/resource"))
assert.NotPanics(t, func() { c.Redirect(300, "/resource") }) assert.NoError(t, c.Redirect(300, "/resource"))
assert.NotPanics(t, func() { c.Redirect(308, "/resource") }) assert.NoError(t, c.Redirect(308, "/resource"))
} }
func TestContextNegotiationFormat(t *testing.T) { func TestContextNegotiationFormat(t *testing.T) {

View File

@ -5,6 +5,7 @@
package render package render
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
) )
@ -17,7 +18,7 @@ type Redirect struct {
func (r Redirect) Render(w http.ResponseWriter) error { func (r Redirect) Render(w http.ResponseWriter) error {
if (r.Code < 300 || r.Code > 308) && r.Code != 201 { if (r.Code < 300 || r.Code > 308) && r.Code != 201 {
panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code)) return errors.New(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
} }
http.Redirect(w, r.Request, r.Location, r.Code) http.Redirect(w, r.Request, r.Location, r.Code)
return nil return nil