| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -104,6 +104,9 @@ r := render.New(render.Options{ | |||
| 104 | 104 | HTMLTemplateOption: "missingkey=error", // Sets the option value for HTML templates. See https://pkg.go.dev/html/template#Template.Option for a list of known options. | |
| 105 | 105 | RequirePartials: true, // Return an error if a template is missing a partial used in a layout. | |
| 106 | 106 | DisableHTTPErrorRendering: true, // Disables automatic rendering of http.StatusInternalServerError when an error occurs. | |
| 107 | + JSONEncoder: func(w io.Writer) render.JSONEncoder { // Use jsoniter "github.com/json-iterator" | ||
| 108 | + return jsoniter.NewEncoder(w) | ||
| 109 | + }, | ||
| 107 | 110 | }) | |
| 108 | 111 | // ... | |
| 109 | 112 | ~~~ | |
@@ -146,6 +149,7 @@ r := render.New(render.Options{ | |||
| 146 | 149 | DisableHTTPErrorRendering: false, | |
| 147 | 150 | RenderPartialsWithoutPrefix: false, | |
| 148 | 151 | BufferPool: GenericBufferPool, | |
| 152 | + JSONEncoder: nil, | ||
| 149 | 153 | }) | |
| 150 | 154 | ~~~ | |
| 151 | 155 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,13 +34,21 @@ type HTML struct { | |||
| 34 | 34 | bp GenericBufferPool | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | + // JSONEncoder match encoding/json.Encoder capabilities. | ||
| 38 | + type JSONEncoder interface { | ||
| 39 | + Encode(v interface{}) error | ||
| 40 | + SetEscapeHTML(on bool) | ||
| 41 | + SetIndent(prefix, indent string) | ||
| 42 | + } | ||
| 43 | + | ||
| 37 | 44 | // JSON built-in renderer. | |
| 38 | 45 | type JSON struct { | |
| 39 | 46 | Head | |
| 40 | 47 | Indent bool | |
| 41 | 48 | UnEscapeHTML bool | |
| 42 | 49 | Prefix []byte | |
| 43 | 50 | StreamingJSON bool | |
| 51 | + NewEncoder func(w io.Writer) JSONEncoder | ||
| 44 | 52 | } | |
| 45 | 53 | ||
| 46 | 54 | // JSONP built-in renderer. | |
@@ -114,7 +122,7 @@ func (j JSON) Render(w io.Writer, v interface{}) error { | |||
| 114 | 122 | } | |
| 115 | 123 | ||
| 116 | 124 | var buf bytes.Buffer | |
| 117 | - encoder := json.NewEncoder(&buf) | ||
| 125 | + encoder := j.NewEncoder(&buf) | ||
| 118 | 126 | encoder.SetEscapeHTML(!j.UnEscapeHTML) | |
| 119 | 127 | ||
| 120 | 128 | if j.Indent { | |
@@ -155,7 +163,7 @@ func (j JSON) renderStreamingJSON(w io.Writer, v interface{}) error { | |||
| 155 | 163 | _, _ = w.Write(j.Prefix) | |
| 156 | 164 | } | |
| 157 | 165 | ||
| 158 | - encoder := json.NewEncoder(w) | ||
| 166 | + encoder := j.NewEncoder(w) | ||
| 159 | 167 | encoder.SetEscapeHTML(!j.UnEscapeHTML) | |
| 160 | 168 | ||
| 161 | 169 | if j.Indent { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ package render | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
| 5 | + "encoding/json" | ||
| 5 | 6 | "fmt" | |
| 6 | 7 | "html/template" | |
| 7 | 8 | "io" | |
@@ -117,6 +118,8 @@ type Options struct { | |||
| 117 | 118 | // BufferPool to use when rendering HTML templates. If none is supplied | |
| 118 | 119 | // defaults to SizedBufferPool of size 32 with 512KiB buffers. | |
| 119 | 120 | BufferPool GenericBufferPool | |
| 121 | + // Custom JSON Encoder. Default to encoding/json.NewEncoder. | ||
| 122 | + JSONEncoder func(w io.Writer) JSONEncoder | ||
| 120 | 123 | } | |
| 121 | 124 | ||
| 122 | 125 | // HTMLOptions is a struct for overriding some rendering Options for specific HTML call. | |
@@ -209,6 +212,12 @@ func (r *Render) prepareOptions() { | |||
| 209 | 212 | } else { | |
| 210 | 213 | r.lock = &emptyLock{} | |
| 211 | 214 | } | |
| 215 | + | ||
| 216 | + if r.opt.JSONEncoder == nil { | ||
| 217 | + r.opt.JSONEncoder = func(w io.Writer) JSONEncoder { | ||
| 218 | + return json.NewEncoder(w) | ||
| 219 | + } | ||
| 220 | + } | ||
| 212 | 221 | } | |
| 213 | 222 | ||
| 214 | 223 | func (r *Render) CompileTemplates() { | |
@@ -526,6 +535,7 @@ func (r *Render) JSON(w io.Writer, status int, v interface{}) error { | |||
| 526 | 535 | Prefix: r.opt.PrefixJSON, | |
| 527 | 536 | UnEscapeHTML: r.opt.UnEscapeHTML, | |
| 528 | 537 | StreamingJSON: r.opt.StreamingJSON, | |
| 538 | + NewEncoder: r.opt.JSONEncoder, | ||
| 529 | 539 | } | |
| 530 | 540 | ||
| 531 | 541 | return r.Render(w, j, v) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ package render | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "encoding/json" | |
| 5 | + "io" | ||
| 5 | 6 | "math" | |
| 6 | 7 | "net/http" | |
| 7 | 8 | "net/http/httptest" | |
@@ -13,6 +14,28 @@ type Greeting struct { | |||
| 13 | 14 | Two string `json:"two"` | |
| 14 | 15 | } | |
| 15 | 16 | ||
| 17 | + type TestEncoder struct { | ||
| 18 | + JSONEncoder | ||
| 19 | + w io.Writer | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + func (e TestEncoder) NewEncoder(w io.Writer) JSONEncoder { | ||
| 23 | + return TestEncoder{w: w} | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + func (e TestEncoder) Encode(v interface{}) error { | ||
| 27 | + e.w.Write([]byte(e.String())) | ||
| 28 | + return nil | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + func (e TestEncoder) SetEscapeHTML(on bool) {} | ||
| 32 | + | ||
| 33 | + func (e TestEncoder) SetIndent(prefix, indent string) {} | ||
| 34 | + | ||
| 35 | + func (e TestEncoder) String() string { | ||
| 36 | + return "{\"one\":\"world\",\"two\":\"hello\"}" | ||
| 37 | + } | ||
| 38 | + | ||
| 16 | 39 | func TestJSONBasic(t *testing.T) { | |
| 17 | 40 | render := New() | |
| 18 | 41 | ||
@@ -346,3 +369,46 @@ func TestJSONDisabledCharset(t *testing.T) { | |||
| 346 | 369 | expect(t, res.Header().Get(ContentType), ContentJSON) | |
| 347 | 370 | expect(t, res.Body.String(), "{\"one\":\"hello\",\"two\":\"world\"}") | |
| 348 | 371 | } | |
| 372 | + | ||
| 373 | + func TestJSONEncoder(t *testing.T) { | ||
| 374 | + render := New(Options{ | ||
| 375 | + JSONEncoder: TestEncoder{}.NewEncoder, | ||
| 376 | + }) | ||
| 377 | + | ||
| 378 | + var err error | ||
| 379 | + | ||
| 380 | + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| 381 | + err = render.JSON(w, 299, Greeting{"hello", "world"}) | ||
| 382 | + }) | ||
| 383 | + | ||
| 384 | + res := httptest.NewRecorder() | ||
| 385 | + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/foo", nil) | ||
| 386 | + h.ServeHTTP(res, req) | ||
| 387 | + | ||
| 388 | + expectNil(t, err) | ||
| 389 | + expect(t, res.Code, 299) | ||
| 390 | + expect(t, res.Header().Get(ContentType), ContentJSON+"; charset=UTF-8") | ||
| 391 | + expect(t, res.Body.String(), TestEncoder{}.String()) | ||
| 392 | + } | ||
| 393 | + | ||
| 394 | + func TestJSONEncoderStream(t *testing.T) { | ||
| 395 | + render := New(Options{ | ||
| 396 | + JSONEncoder: TestEncoder{}.NewEncoder, | ||
| 397 | + StreamingJSON: true, | ||
| 398 | + }) | ||
| 399 | + | ||
| 400 | + var err error | ||
| 401 | + | ||
| 402 | + h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| 403 | + err = render.JSON(w, 299, Greeting{"hello", "world"}) | ||
| 404 | + }) | ||
| 405 | + | ||
| 406 | + res := httptest.NewRecorder() | ||
| 407 | + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/foo", nil) | ||
| 408 | + h.ServeHTTP(res, req) | ||
| 409 | + | ||
| 410 | + expectNil(t, err) | ||
| 411 | + expect(t, res.Code, 299) | ||
| 412 | + expect(t, res.Header().Get(ContentType), ContentJSON+"; charset=UTF-8") | ||
| 413 | + expect(t, res.Body.String(), TestEncoder{}.String()) | ||
| 414 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments