Difference Between JSON, SecureJSON, PureJSON, and IndentedJSON in Gin
TLDR: Gin provides four JSON renderers in its render package: JSON for standard serialization with HTML escaping enabled; IndentedJSON for human-readable, pretty-printed output; SecureJSON to prevent JSON array hijacking attacks via prefix injection; and PureJSON for unescaped, streaming encoding that bypasses HTML entity translation. All implement the render.Renderer interface but differ in security controls, formatting, and memory allocation strategies.
The Gin web framework offers multiple ways to serialize JSON responses depending on your security, readability, and performance requirements. Understanding the difference between JSON, SecureJSON, PureJSON, and IndentedJSON in Gin allows you to select the optimal renderer for your API endpoints. These four concrete types reside in github.com/gin-gonic/gin/render and implement the render.Renderer interface, each manipulating the JSON payload differently before writing to the http.ResponseWriter.
Standard JSON Rendering
The JSON type provides the default serialization behavior used by c.JSON(). In render/json.go at lines 56-60, the Render method calls WriteJSON, which marshals the value using json.API.Marshal and writes the bytes directly to the response writer.
This renderer enables HTML escaping by default, translating characters like <, >, and & into their Unicode escape sequences (\u003c, \u003e, \u0026). It sets the content-type header to application/json; charset=utf-8 and produces compact, single-line output without indentation.
c.JSON(http.StatusOK, gin.H{
"msg": "hello",
"count": 5,
"html": "<script>test</script>", // Escaped to \u003cscript\u003e
})
Pretty-Printed Responses with IndentedJSON
Use IndentedJSON when you need human-readable output for debugging or development APIs. According to the source in render/json.go at lines 77-85, this renderer invokes json.API.MarshalIndent with a four-space prefix and indent string.
The content-type header remains identical to standard JSON (application/json; charset=utf-8), but the response body includes newline characters and indentation for nested structures. This convenience trades payload size and slight performance for improved readability.
c.IndentedJSON(http.StatusOK, gin.H{
"users": []string{"alice", "bob"},
"meta": map[string]int{"total": 2},
})
Security-Hardened JSON with SecureJSON
The SecureJSON renderer mitigates JSON hijacking attacks where malicious sites load sensitive JSON arrays via <script> tags. As implemented in render/json.go at lines 93-109, this renderer checks if the marshaled data starts with [ and ends with ] using bytes.HasPrefix and bytes.HasSuffix.
If the top-level value is an array, SecureJSON writes the configured prefix—defaulting to ")]}',\n" via JSONSecurePrefix—before the JSON bytes. This prefix invalidates the JavaScript array literal syntax, preventing unauthorized access while remaining valid JSON for compliant parsers.
// Protects against hijacking when returning arrays
c.SecureJSON(http.StatusOK, []string{"secret1", "secret2"})
Unescaped Streaming with PureJSON
PureJSON disables HTML escaping and streams encoding directly to the client, reducing memory overhead for large payloads. The implementation in render/json.go at lines 83-89 creates a new encoder via json.API.NewEncoder(w), calls SetEscapeHTML(false), and streams the output without buffering an intermediate byte slice.
Use this renderer when your payload contains pre-sanitized HTML or when you need to avoid the default escaping overhead. Be cautious: disabling escaping can expose XSS vulnerabilities if the data contains untrusted user input.
// Skips HTML escaping, outputs raw <script> tags
c.PureJSON(http.StatusOK, map[string]interface{}{
"html": "<script>alert('xss');</script>",
})
Summary
- JSON: The default renderer at
render/json.go:56-60that balances speed and safety with HTML escaping and compact output. - IndentedJSON: Pretty-prints with four-space indentation via
MarshalIndentatrender/json.go:77-85, ideal for development. - SecureJSON: Injects the
")]}',\n"prefix before top-level arrays atrender/json.go:93-109to prevent JSON hijacking. - PureJSON: Streams unescaped JSON directly to
http.ResponseWriteratrender/json.go:83-89, optimizing for performance and HTML fidelity.
Frequently Asked Questions
What is the main difference between JSON and PureJSON in Gin?
Standard JSON marshals to an intermediate byte slice with HTML escaping enabled, protecting against XSS but adding overhead. PureJSON streams directly to the response writer via json.API.NewEncoder with SetEscapeHTML(false), eliminating buffering and preserving raw HTML characters like < and >.
When should I use SecureJSON instead of regular JSON?
Use SecureJSON when your endpoint returns JSON arrays as the top-level element and the data contains sensitive information. According to the gin-gonic/gin source code, it prefixes array responses with ")]}',\n" to prevent JSON hijacking attacks where third-party sites could steal array data via script tags.
Does IndentedJSON affect performance compared to standard JSON?
Yes. IndentedJSON calls MarshalIndent rather than Marshal, producing larger payloads due to whitespace and requiring additional formatting CPU cycles. The implementation in render/json.go uses four-space indentation, significantly increasing response size for large nested objects compared to the compact JSON renderer.
Can I configure the indentation width for IndentedJSON?
No. The indentation is hardcoded to four spaces in render/json.go at lines 77-85. If you require custom indentation or alternative formatting, you must marshal the JSON manually using json.MarshalIndent with your preferred parameters and write it using c.Data or c.String.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →