mirror of https://github.com/gin-gonic/gin.git
add a method to set the indentJsonIndentString used in Context.IndentedJSON
This commit is contained in:
parent
4427ca4a60
commit
2fc888a61d
|
@ -859,7 +859,7 @@ func (c *Context) HTML(code int, name string, obj interface{}) {
|
||||||
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
|
// WARNING: we recommend to use this only for development purposes 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{}) {
|
||||||
c.Render(code, render.IndentedJSON{Data: obj})
|
c.Render(code, render.IndentedJSON{IndentString: c.engine.indentJsonIndentString, Data: obj})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecureJSON serializes the given struct as Secure JSON into the response body.
|
// SecureJSON serializes the given struct as Secure JSON into the response body.
|
||||||
|
|
33
gin.go
33
gin.go
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/internal/bytesconv"
|
"github.com/gin-gonic/gin/internal/bytesconv"
|
||||||
|
@ -19,6 +20,9 @@ import (
|
||||||
|
|
||||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
|
|
||||||
|
// A space string
|
||||||
|
var spaceString = string(32)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
default404Body = []byte("404 page not found")
|
default404Body = []byte("404 page not found")
|
||||||
default405Body = []byte("405 method not allowed")
|
default405Body = []byte("405 method not allowed")
|
||||||
|
@ -102,16 +106,17 @@ type Engine struct {
|
||||||
// See the PR #1817 and issue #1644
|
// See the PR #1817 and issue #1644
|
||||||
RemoveExtraSlash bool
|
RemoveExtraSlash bool
|
||||||
|
|
||||||
delims render.Delims
|
delims render.Delims
|
||||||
secureJsonPrefix string
|
secureJsonPrefix string
|
||||||
HTMLRender render.HTMLRender
|
HTMLRender render.HTMLRender
|
||||||
FuncMap template.FuncMap
|
FuncMap template.FuncMap
|
||||||
allNoRoute HandlersChain
|
allNoRoute HandlersChain
|
||||||
allNoMethod HandlersChain
|
allNoMethod HandlersChain
|
||||||
noRoute HandlersChain
|
noRoute HandlersChain
|
||||||
noMethod HandlersChain
|
noMethod HandlersChain
|
||||||
pool sync.Pool
|
pool sync.Pool
|
||||||
trees methodTrees
|
trees methodTrees
|
||||||
|
indentJsonIndentString string
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ IRouter = &Engine{}
|
var _ IRouter = &Engine{}
|
||||||
|
@ -145,6 +150,7 @@ func New() *Engine {
|
||||||
trees: make(methodTrees, 0, 9),
|
trees: make(methodTrees, 0, 9),
|
||||||
delims: render.Delims{Left: "{{", Right: "}}"},
|
delims: render.Delims{Left: "{{", Right: "}}"},
|
||||||
secureJsonPrefix: "while(1);",
|
secureJsonPrefix: "while(1);",
|
||||||
|
indentJsonIndentString: strings.Repeat(spaceString, 4),
|
||||||
}
|
}
|
||||||
engine.RouterGroup.engine = engine
|
engine.RouterGroup.engine = engine
|
||||||
engine.pool.New = func() interface{} {
|
engine.pool.New = func() interface{} {
|
||||||
|
@ -177,6 +183,13 @@ func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndentJsonIndentSpaceNum sets the indentJsonIndentString used in Context.IndentedJSON.
|
||||||
|
// When we use Context.IndentedJSON, we can use custom indentation to render the response.
|
||||||
|
func (engine *Engine) IndentJsonIndentSpaceNum(spaceNum int) *Engine {
|
||||||
|
engine.indentJsonIndentString = strings.Repeat(spaceString, spaceNum)
|
||||||
|
return engine
|
||||||
|
}
|
||||||
|
|
||||||
// LoadHTMLGlob loads HTML files identified by glob pattern
|
// LoadHTMLGlob loads HTML files identified by glob pattern
|
||||||
// and associates the result with HTML renderer.
|
// and associates the result with HTML renderer.
|
||||||
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||||
|
|
35
gin_test.go
35
gin_test.go
|
@ -6,13 +6,16 @@ package gin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -544,3 +547,35 @@ func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo)
|
||||||
|
|
||||||
func handlerTest1(c *Context) {}
|
func handlerTest1(c *Context) {}
|
||||||
func handlerTest2(c *Context) {}
|
func handlerTest2(c *Context) {}
|
||||||
|
|
||||||
|
// Engine.IndentJsonIndentSpaceNum
|
||||||
|
func TestEngine_IndentJsonIndentSpaceNum(t *testing.T) {
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
spaceNum := rand.Intn(10)
|
||||||
|
|
||||||
|
router := Default()
|
||||||
|
defaultResponse := H{"name": "test", "age": 20}
|
||||||
|
router.IndentJsonIndentSpaceNum(spaceNum)
|
||||||
|
router.GET("/test", func(c *Context) {
|
||||||
|
c.IndentedJSON(200, defaultResponse)
|
||||||
|
})
|
||||||
|
s := httptest.NewServer(router)
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "/test", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
router.ServeHTTP(rr, req)
|
||||||
|
if rr.Code != http.StatusOK {
|
||||||
|
t.Fatal("error code: ", rr.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
except, _ := json.MarshalIndent(defaultResponse, "", strings.Repeat(spaceString, spaceNum))
|
||||||
|
|
||||||
|
assert.Equal(t, rr.Body.Bytes(), except)
|
||||||
|
t.Log(rr.Body.String())
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ type JSON struct {
|
||||||
|
|
||||||
// IndentedJSON contains the given interface object.
|
// IndentedJSON contains the given interface object.
|
||||||
type IndentedJSON struct {
|
type IndentedJSON struct {
|
||||||
|
IndentString string
|
||||||
Data interface{}
|
Data interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ func WriteJSON(w http.ResponseWriter, obj interface{}) error {
|
||||||
// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
|
// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType.
|
||||||
func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
||||||
r.WriteContentType(w)
|
r.WriteContentType(w)
|
||||||
jsonBytes, err := json.MarshalIndent(r.Data, "", " ")
|
jsonBytes, err := json.MarshalIndent(r.Data, "", r.IndentString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestRenderIndentedJSON(t *testing.T) {
|
||||||
"bar": "foo",
|
"bar": "foo",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := (IndentedJSON{data}).Render(w)
|
err := (IndentedJSON{" ", data}).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
||||||
|
@ -67,7 +67,7 @@ func TestRenderIndentedJSONPanics(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
err := (IndentedJSON{data}).Render(w)
|
err := (IndentedJSON{"", data}).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue