JSON Formatter Go — MarshalIndent() गाइड

·Systems Engineer·समीक्षकTobias Müller·प्रकाशित

मुफ़्त JSON Formatter & Beautifier को सीधे अपने ब्राउज़र में उपयोग करें — इंस्टॉलेशन की ज़रूरत नहीं।

JSON Formatter & Beautifier ऑनलाइन आज़माएं →

जब मैं Go microservice पर काम करता हूँ और API response या config file inspect करनी होती है, compact JSON पहली बाधा बन जाती है — सैकड़ों nested fields वाली एक लाइन एक नज़र में लगभग कुछ नहीं बताती। Go में JSON format करने के लिए, standard library आपको सब कुछ देती है: json.MarshalIndent पहले से encoding/json में built-in है, हर Go installation के साथ आती है, और zero third-party dependencies की ज़रूरत है। यह guide पूरी तस्वीर cover करता है: struct tags, custom MarshalJSON() implementations, raw bytes को reformat करने के लिए json.Indent, json.Decoder से large files streaming, high-throughput paths के लिए go-json कब use करें, और terminal में quick formatting के लिए CLI one-liners। सभी examples Go 1.21+ use करते हैं।

  • json.MarshalIndent(v, "", "\t") standard library है — zero dependencies, हर Go install के साथ आती है।
  • Struct tags json:"field_name,omitempty" serialization keys control करते हैं और zero-value fields को output से हटाते हैं।
  • किसी भी type पर MarshalJSON() implement करें और उसके JSON representation को पूरी तरह control करें।
  • json.Indent() पहले से marshal हुए []byte को struct re-parse किए बिना reformat करता है — raw bytes के लिए तेज़।
  • बड़ी files (>100 MB) के लिए: सब कुछ memory में लोड किए बिना streaming के लिए json.Decoder के साथ Token() use करें।
  • go-json, high-throughput APIs के लिए encoding/json से 3–5× तेज़ drop-in replacement है।

JSON Formatting क्या है?

JSON formatting — जिसे pretty-printing भी कहते हैं — एक compact, minified JSON string को consistent indentation और line breaks के साथ human-readable layout में transform करता है। underlying data identical होता है; केवल whitespace बदलती है। Compact JSON network transfer के लिए optimal है जहाँ हर byte मायने रखती है; formatted JSON debugging, code review, log inspection, और config file authoring के लिए optimal है। Go का encoding/json package एक single function call से दोनों modes handle करता है — json.Marshal और json.MarshalIndent के बीच choose करके compact और indented output में toggle करें।

Before · json
After · json
{"service":"payments","port":8443,"workers":4}
{
	"service": "payments",
	"port": 8443,
	"workers": 4
}

json.MarshalIndent() — स्टैंडर्ड लाइब्रेरी का तरीका

json.MarshalIndent Go standard library के हिस्से encoding/json package में रहता है — कोई go get नहीं चाहिए। इसका signature है MarshalIndent(v any, prefix, indent string) ([]byte, error): prefix string हर output line के आगे जुड़ती है (लगभग हमेशा खाली छोड़ी जाती है), और indent हर nesting level पर एक बार repeat होती है। Tabs के लिए "\t" या two spaces के लिए " " pass करें।

Go — minimal working example
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type ServiceConfig struct {
	Host       string   `json:"host"`
	Port       int      `json:"port"`
	Workers    int      `json:"workers"`
	TLSEnabled bool     `json:"tls_enabled"`
	AllowedIPs []string `json:"allowed_ips"`
}

func main() {
	cfg := ServiceConfig{
		Host:       "payments-api.internal",
		Port:       8443,
		Workers:    8,
		TLSEnabled: true,
		AllowedIPs: []string{"10.0.0.0/8", "172.16.0.0/12"},
	}

	data, err := json.MarshalIndent(cfg, "", "	")
	if err != nil {
		log.Fatalf("marshal config: %v", err)
	}
	fmt.Println(string(data))
}
// {
// 	"host": "payments-api.internal",
// 	"port": 8443,
// 	"workers": 8,
// 	"tls_enabled": true,
// 	"allowed_ips": [
// 		"10.0.0.0/8",
// 		"172.16.0.0/12"
// 	]
// }

Tabs और spaces के बीच choice ज़्यादातर team convention है। कई Go projects tabs prefer करते हैं क्योंकि gofmt (जो Go source code format करता है) tabs use करता है। Two-space या four-space indentation तब सामान्य है जब JSON किसी JavaScript या Python consumer के लिए है। यहाँ same struct दोनों indent styles के साथ side by side:

Go — tabs vs spaces
// Tab indent — Go-native tooling में preferred
data, _ := json.MarshalIndent(cfg, "", "	")
// {
// 	"host": "payments-api.internal",
// 	"port": 8443
// }

// Two-space indent — JS/Python consumers वाली APIs के लिए सामान्य
data, _ = json.MarshalIndent(cfg, "", "  ")
// {
//   "host": "payments-api.internal",
//   "port": 8443
// }

// Four-space indent
data, _ = json.MarshalIndent(cfg, "", "    ")
// {
//     "host": "payments-api.internal",
//     "port": 8443
// }
नोट:Compact output चाहिए — network payloads, cache values, या कोई भी path जहाँ binary size मायने रखती हो — तो json.Marshal(v) use करें। यह same value argument लेता है और same error semantics रखता है, लेकिन बिना किसी whitespace के single-line JSON बनाता है।

Struct Tags — Field Names और Omitempty को Control करना

Go struct tags field declarations के बाद रखे गए string literals हैं जो encoding/jsonको बताते हैं कि हर field को कैसे serialize करना है। तीन key directives हैं: json:"name" output में field का नाम बदलता है, omitempty field को तब छोड़ता है जब वह अपने type की zero value रखती हो, और json:"-" field को पूरी तरह exclude करता है — passwords, internal identifiers, या ऐसी fields के लिए उपयोगी जो service boundary से बाहर नहीं जानी चाहिए।

Go — API response के लिए struct tags
type UserProfile struct {
	ID          string  `json:"id"`
	Email       string  `json:"email"`
	DisplayName string  `json:"display_name,omitempty"`  // empty string होने पर छोड़ें
	AvatarURL   *string `json:"avatar_url,omitempty"`    // nil pointer होने पर छोड़ें
	IsAdmin     bool    `json:"is_admin,omitempty"`      // false होने पर छोड़ें
	passwordHash string                                   // unexported — auto excluded
}

// सभी optional fields भरे हुए user के साथ
full := UserProfile{
	ID: "usr_7b3c", Email: "raj.kumar@udaharan.com",
	DisplayName: "राज कुमार", IsAdmin: true,
}
// {
//   "id": "usr_7b3c",
//   "email": "raj.kumar@udaharan.com",
//   "display_name": "राज कुमार",
//   "is_admin": true
// }

// बिना optional fields वाला user — पूरी तरह छोड़ दिए जाते हैं
minimal := UserProfile{ID: "usr_2a91", Email: "priya.sharma@udaharan.com"}
// {
//   "id": "usr_2a91",
//   "email": "priya.sharma@udaharan.com"
// }

json:"-" tag उन fields के लिए सही choice है जिन्हें उनकी value चाहे जो हो, unconditionally exclude करना है — आमतौर पर secrets, internal tracking fields, या ऐसा data जो memory में सही है लेकिन किसी भी external system में serialize नहीं होना चाहिए।

Go — sensitive fields exclude करना
type AuthToken struct {
	TokenID      string `json:"token_id"`
	Subject      string `json:"sub"`
	IssuedAt     int64  `json:"iat"`
	ExpiresAt    int64  `json:"exp"`
	SigningKey    []byte `json:"-"`   // कभी serialize नहीं होता
	RefreshToken string `json:"-"`   // कभी serialize नहीं होता
}

tok := AuthToken{
	TokenID: "tok_8f2a", Subject: "usr_7b3c",
	IssuedAt: 1741614120, ExpiresAt: 1741617720,
	SigningKey: []byte("गुप्त"), RefreshToken: "rt_9e4f",
}
data, _ := json.MarshalIndent(tok, "", "  ")
// {
//   "token_id": "tok_8f2a",
//   "sub": "usr_7b3c",
//   "iat": 1741614120,
//   "exp": 1741617720
// }
// SigningKey और RefreshToken कभी नहीं दिखते
नोट:Unexported (lowercase) struct fields हमेशा encoding/json द्वारा किसी भी tag की परवाह किए बिना exclude होते हैं। Unexported fields में json:"-" जोड़ने की ज़रूरत नहीं — exclusion automatic है और override नहीं किया जा सकता।

Custom MarshalJSON() — Non-Standard Types Handle करना

कोई भी Go type MarshalJSON() ([]byte, error) method define करके json.Marshaler interface implement कर सकता है। जब encoding/json ऐसे type से मिलता है, तो वह default reflection-based marshaling की बजाय method call करता है। यह domain types के लिए canonical Go pattern है जिन्हें specific wire representation की ज़रूरत है — monetary values, status enums, custom time formats, या कोई भी type जो data को उस तरह store करता है जो serialize होना चाहिए उससे अलग।

Custom Type — पैसे के साथ Cents-to-Decimal Conversion

Go — Money के लिए custom MarshalJSON
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type Money struct {
	Amount   int64  // floating-point drift से बचने के लिए paise में store
	Currency string
}

func (m Money) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Amount   float64 `json:"amount"`
		Currency string  `json:"currency"`
		Display  string  `json:"display"`
	}{
		Amount:   float64(m.Amount) / 100,
		Currency: m.Currency,
		Display:  fmt.Sprintf("%s %.2f", m.Currency, float64(m.Amount)/100),
	})
}

type Invoice struct {
	ID       string `json:"id"`
	Subtotal Money  `json:"subtotal"`
	Tax      Money  `json:"tax"`
	Total    Money  `json:"total"`
}

func main() {
	inv := Invoice{
		ID:       "inv_9a2f91bc",
		Subtotal: Money{Amount: 1990000, Currency: "INR"},
		Tax:      Money{Amount: 159200, Currency: "INR"},
		Total:    Money{Amount: 2149200, Currency: "INR"},
	}
	data, err := json.MarshalIndent(inv, "", "  ")
	if err != nil {
		log.Fatalf("marshal invoice: %v", err)
	}
	fmt.Println(string(data))
}
// {
//   "id": "inv_9a2f91bc",
//   "subtotal": { "amount": 19900, "currency": "INR", "display": "INR 19900.00" },
//   "tax":      { "amount": 1592, "currency": "INR", "display": "INR 1592.00" },
//   "total":    { "amount": 21492, "currency": "INR", "display": "INR 21492.00" }
// }

Status Enum — String Representation

Go — status enum के लिए custom MarshalJSON
type OrderStatus int

const (
	StatusPending OrderStatus = iota
	StatusPaid
	StatusShipped
	StatusCancelled
)

var orderStatusNames = map[OrderStatus]string{
	StatusPending:   "pending",
	StatusPaid:      "paid",
	StatusShipped:   "shipped",
	StatusCancelled: "cancelled",
}

func (s OrderStatus) MarshalJSON() ([]byte, error) {
	name, ok := orderStatusNames[s]
	if !ok {
		return nil, fmt.Errorf("अज्ञात order status: %d", s)
	}
	return json.Marshal(name)
}

type Order struct {
	ID     string      `json:"id"`
	Status OrderStatus `json:"status"`
}

o := Order{ID: "ord_3c7f", Status: StatusShipped}
data, _ := json.MarshalIndent(o, "", "  ")
// {
//   "id": "ord_3c7f",
//   "status": "shipped"
// }
नोट:हमेशा MarshalJSON() और UnmarshalJSON() दोनों को साथ implement करें। अगर आप केवल marshaling implement करते हैं, तो JSON के माध्यम से type का round-tripping (serialize → store → deserialize) चुपचाप structure खो देगा या गलत type return करेगा। यह pair एक contract बनाता है कि type JSON round-trip से बच सकता है।

UUID — String के रूप में Serialize करें

Go की standard library में कोई UUID type नहीं है। सबसे सामान्य choice github.com/google/uuid है, जो पहले से MarshalJSON() implement करता है और quoted RFC 4122 string के रूप में serialize करता है। अगर आप raw [16]byte या custom ID type use करते हैं, तो JSON output में base64-encoded binary blobs से बचने के लिए interface खुद implement करें।

Go 1.21+ — UUID serialization
import (
    "encoding/json"
    "fmt"

    "github.com/google/uuid"
)

type AuditEvent struct {
    EventID   uuid.UUID `json:"event_id"`   // "550e8400-e29b-41d4-a716-446655440000" के रूप में serialize होता है
    SessionID uuid.UUID `json:"session_id"`
    Action    string    `json:"action"`
    ActorID   string    `json:"actor_id"`
    OccuredAt string    `json:"occurred_at"`
}

event := AuditEvent{
    EventID:   uuid.New(),
    SessionID: uuid.MustParse("550e8400-e29b-41d4-a716-446655440000"),
    Action:    "user.password_changed",
    ActorID:   "usr_7f3a91bc",
    OccuredAt: "2026-03-10T14:22:00Z",
}

data, _ := json.MarshalIndent(event, "", "  ")
fmt.Println(string(data))
// {
//   "event_id": "a4b2c1d0-...",
//   "session_id": "550e8400-e29b-41d4-a716-446655440000",
//   "action": "user.password_changed",
//   "actor_id": "usr_7f3a91bc",
//   "occurred_at": "2026-03-10T14:22:00Z"
// }
नोट:अगर आप UUIDs को custom type के बिना [16]byte के रूप में store करते हैं, encoding/json उन्हें base64 string के रूप में encode करेगा — जैसे "VQ6EAOKbQdSnFkRmVUQAAA=="। हमेशा proper UUID type use करें या canonical hyphenated string format emit करने के लिए MarshalJSON() implement करें।

json.MarshalIndent() पैरामीटर संदर्भ

Function signature है func MarshalIndent(v any, prefix, indent string) ([]byte, error)। दोनों prefix और indent string literals हैं — Python के indent=4 जैसा कोई numeric shorthand नहीं है।

Parameter
Type
विवरण
v
any
marshal की जाने वाली वैल्यू — struct, map, slice, या primitive
prefix
string
आउटपुट की हर लाइन के शुरू में जोड़ी जाने वाली string (आमतौर पर "")
indent
string
हर इंडेंटेशन लेवल के लिए इस्तेमाल होने वाली string ("\t" या " ")

सामान्य struct tag options:

Tag
प्रभाव
json:"name"
JSON आउटपुट में field का नाम name रखें
json:"name,omitempty"
नाम बदलें + zero value होने पर छोड़ें (nil, "", 0, false)
json:"-"
इस field को JSON आउटपुट से हमेशा बाहर करें
json:",string"
संख्या या bool को JSON string value के रूप में encode करें

json.Indent() — मौजूदा JSON Bytes को Reformat करना

जब आपके पास पहले से JSON का []byte हो — HTTP response body, Postgres के jsonb column, या os.ReadFile से पढ़ी गई file — तो pretty-print से पहले struct define करके unmarshal करने की ज़रूरत नहीं। json.Indent raw bytes को सीधे एक bytes.Buffer में indented output लिखकर reformat करता है।

Go — raw bytes पर json.Indent
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	// upstream service से raw JSON payload simulate करना
	raw := []byte(`{"trace_id":"tr_9a2f","service":"checkout","latency_ms":342,"error":null}`)

	var buf bytes.Buffer
	if err := json.Indent(&buf, raw, "", "	"); err != nil {
		log.Fatalf("indent: %v", err)
	}
	fmt.Println(buf.String())
}
// {
// 	"trace_id": "tr_9a2f",
// 	"service": "checkout",
// 	"latency_ms": 342,
// 	"error": null
// }

Microservices में मैं जो सामान्य pattern use करता हूँ वह है structured logs में लिखने से पहले json.Indent call करना — यह negligible overhead जोड़ता है और incident के दौरान log entries को बहुत आसानी से पढ़ने योग्य बनाता है। यह function HTTP responses log करने, stored JSON strings को pretty-print करने, और format-on-read pipelines में विशेष रूप से उपयोगी है जहाँ struct definition available नहीं है।

Go — debug logging के लिए json.Indent
func logResponse(logger *slog.Logger, statusCode int, body []byte) {
	var pretty bytes.Buffer
	if err := json.Indent(&pretty, body, "", "  "); err != nil {
		// Body valid JSON नहीं है — raw log करें
		logger.Debug("upstream response", "status", statusCode, "body", string(body))
		return
	}
	logger.Debug("upstream response", "status", statusCode, "body", pretty.String())
}
चेतावनी:json.Indent JSON को उससे परे fully validate नहीं करता जो whitespace insert करने के लिए structurally ज़रूरी है। Full syntax validation के लिए, पहले json.Valid(data) call करें और indent attempt से पहले false case handle करें।

File और HTTP Response से JSON Format करना

Go services में दो सबसे सामान्य real-world scenarios हैं: disk पर file से JSON format करना (config files, fixture data, migration seeds) और debug logging या test assertions के लिए HTTP response bodies को pretty-print करना। दोनों same pattern follow करते हैं: bytes पढ़ें, json.Indent call करें या unmarshal करके json.MarshalIndent करें, फिर वापस लिखें या log करें।

File पढ़ें → Format करें → वापस लिखें

Go — JSON file को in place format करना
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

func formatJSONFile(path string) error {
	data, err := os.ReadFile(path)
	if err != nil {
		return fmt.Errorf("पढ़ें %s: %w", path, err)
	}

	if !json.Valid(data) {
		return fmt.Errorf("%s में invalid JSON", path)
	}

	var buf bytes.Buffer
	if err := json.Indent(&buf, data, "", "	"); err != nil {
		return fmt.Errorf("indent %s: %w", path, err)
	}

	if err := os.WriteFile(path, buf.Bytes(), 0644); err != nil {
		return fmt.Errorf("लिखें %s: %w", path, err)
	}
	return nil
}

func main() {
	if err := formatJSONFile("config/database.json"); err != nil {
		log.Fatalf("format config: %v", err)
	}
	fmt.Println("config/database.json सफलतापूर्वक format हुई")
}

HTTP Response → Decode → Debug Logging के लिए Pretty-Print

Go — debug log के लिए HTTP response format करना
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type HealthResponse struct {
	Status    string            `json:"status"`
	Version   string            `json:"version"`
	Checks    map[string]string `json:"checks"`
	UptimeSec int64             `json:"uptime_seconds"`
}

func main() {
	resp, err := http.Get("https://api.payments.internal/v2/health")
	if err != nil {
		log.Fatalf("health check: %v", err)
	}
	defer resp.Body.Close()

	var result HealthResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		log.Fatalf("health response decode करें: %v", err)
	}

	pretty, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		log.Fatalf("health response marshal करें: %v", err)
	}
	fmt.Printf("Health check (%d):
%s
", resp.StatusCode, string(pretty))
}
// Health check (200):
// {
//   "status": "ok",
//   "version": "1.4.2",
//   "checks": {
//     "database": "ok",
//     "cache": "ok",
//     "queue": "degraded"
//   },
//   "uptime_seconds": 172800
// }

Raw Response Body → json.Indent (Struct की ज़रूरत नहीं)

Go — io.ReadAll के साथ raw HTTP body format करना
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	resp, err := http.Get("https://api.payments.internal/v2/health")
	if err != nil {
		log.Fatalf("request: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("body पढ़ें: %v", err)
	}

	var buf bytes.Buffer
	if err := json.Indent(&buf, body, "", "  "); err != nil {
		log.Fatalf("indent: %v", err)
	}
	fmt.Println(buf.String())
}

Go में HTTP Response से JSON Pretty Print करना

ऊपर के दो approaches सबसे सामान्य cases cover करते हैं: typed struct में decode करें फिर json.MarshalIndent call करें (तब सबसे अच्छा जब fields validate या inspect करने हों), या io.ReadAll से raw body bytes पढ़ें और सीधे json.Indent call करें (तब सबसे अच्छा जब struct definition available न हो और quick debug logging चाहिए)। Raw-bytes approach simpler है लेकिन Go type safety या field access नहीं देती — यह purely एक display transformation है। दोनों approaches large response bodies को correctly handle करती हैं जब तक पूरा body memory में fit हो।

Go — दो patterns side by side
// Pattern A: typed decode → MarshalIndent
// तब use करें जब specific fields inspect या validate करने हों
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
pretty, _ := json.MarshalIndent(result, "", "  ")
fmt.Println(string(pretty))

// Pattern B: raw bytes → json.Indent
// Quick debug logging के लिए use करें — struct definition नहीं चाहिए
body, _ := io.ReadAll(resp.Body)
var buf bytes.Buffer
json.Indent(&buf, body, "", "  ")
fmt.Println(buf.String())

Go Projects में Command-Line JSON Formatting

कभी-कभी आपको Go program लिखे बिना सीधे terminal में JSON payload format करनी होती है। ये one-liners वे हैं जो मैं development और incident response के दौरान muscle memory में रखता हूँ।

bash — JSON को Python के built-in formatter में pipe करना
echo '{"service":"payments","port":8443,"workers":4}' | python3 -m json.tool
# {
#     "service": "payments",
#     "port": 8443,
#     "workers": 4
# }
bash — full-featured formatting और filtering के लिए jq में pipe करना
# केवल format करें
cat api-response.json | jq .

# Nested field निकालें
cat api-response.json | jq '.checks.database'

# Array filter करें
cat audit-log.json | jq '.[] | select(.severity == "error")'
bash — stdin के माध्यम से minimal Go main.go में pipe करना
# main.go: stdin पढ़ता है, format करता है, stdout लिखता है
cat <<'EOF' > /tmp/fmt.go
package main
import ("bytes";"encoding/json";"io";"os")
func main() {
    b,_:=io.ReadAll(os.Stdin)
    var buf bytes.Buffer
    json.Indent(&buf,b,"","  ")
    os.Stdout.Write(buf.Bytes())
}
EOF
echo '{"port":8080,"debug":true}' | go run /tmp/fmt.go
नोट:gofmt JSON नहीं बल्कि Go source code format करता है। JSON files को gofmt से pipe न करें — यह या तो error देगा या unrecognizable output बनाएगा। JSON files के लिए jq . या python3 -m json.tool use करें।

उच्च-प्रदर्शन विकल्प — go-json

अधिकांश Go services के लिए, encoding/json काफी तेज़ है। लेकिन अगर JSON marshaling आपके profiler में दिखे — high-throughput REST APIs या हर request पर large structured log lines emit करने वाली services में सामान्य — तो go-json library identical API surface के साथ 3–5× faster drop-in replacement है।

bash — go-json install करें
go get github.com/goccy/go-json
Go — एक import change से encoding/json को go-json से बदलें
package main

import (
	// इसे बदलें:
	// "encoding/json"

	// इससे — identical API, कोई और code changes नहीं:
	json "github.com/goccy/go-json"

	"fmt"
	"log"
)

type AuditEvent struct {
	RequestID string `json:"request_id"`
	UserID    string `json:"user_id"`
	Action    string `json:"action"`
	ResourceID string `json:"resource_id"`
	IPAddress  string `json:"ip_address"`
	DurationMs int    `json:"duration_ms"`
}

func main() {
	event := AuditEvent{
		RequestID: "req_7d2e91", UserID: "usr_4421",
		Action: "invoice.download", ResourceID: "inv_9a2f",
		IPAddress: "203.0.113.45", DurationMs: 23,
	}
	data, err := json.MarshalIndent(event, "", "  ")
	if err != nil {
		log.Fatalf("marshal: %v", err)
	}
	fmt.Println(string(data))
	// Output encoding/json के समान — केवल speed अलग है
}

github.com/bytedance/sonic available सबसे fast Go JSON library है, लेकिन यह केवल amd64 और arm64 पर चलती है (JIT compilation use करती है)। जब portable drop-in चाहिए तो go-json use करें; जब known architecture पर हों और hot path में हर microsecond चाहिए तो sonic तक पहुँचें।

Large JSON Files के साथ काम करना

json.MarshalIndent और json.Indent दोनों को पूरे payload का memory में होना ज़रूरी है। 100 MB से ऊपर की files के लिए — data exports, audit logs, Kafka consumer payloads — input stream करने और records को एक-एक करके process करने के लिए json.Decoder use करें।

json.Decoder से Large JSON Array Streaming

Go — large JSON array को memory में load किए बिना stream करना
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
)

type AuditEvent struct {
	RequestID  string `json:"request_id"`
	UserID     string `json:"user_id"`
	Action     string `json:"action"`
	Severity   string `json:"severity"`
	DurationMs int    `json:"duration_ms"`
}

func processAuditLog(path string) error {
	file, err := os.Open(path)
	if err != nil {
		return fmt.Errorf("खोलें %s: %w", path, err)
	}
	defer file.Close()

	dec := json.NewDecoder(file)

	// Opening '[' token पढ़ें
	if _, err := dec.Token(); err != nil {
		return fmt.Errorf("opening token पढ़ें: %w", err)
	}

	var processed int
	for dec.More() {
		var event AuditEvent
		if err := dec.Decode(&event); err != nil {
			return fmt.Errorf("event %d decode करें: %w", processed, err)
		}
		// एक समय में एक event process करें — constant memory usage
		if event.Severity == "error" {
			fmt.Printf("[ERROR] %s: %s (%dms)
", event.UserID, event.Action, event.DurationMs)
		}
		processed++
	}
	fmt.Printf("%d audit events process हुए
", processed)
	return nil
}

func main() {
	if err := processAuditLog("audit-2026-03.json"); err != nil {
		log.Fatalf("audit log process करें: %v", err)
	}
}

NDJSON — प्रति Line एक JSON Object

Go — NDJSON log stream को line by line process करना
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

type LogLine struct {
	Timestamp  string `json:"ts"`
	Level      string `json:"level"`
	Service    string `json:"service"`
	Message    string `json:"msg"`
	TraceID    string `json:"trace_id"`
	DurationMs int    `json:"duration_ms,omitempty"`
}

func main() {
	file, err := os.Open("service-2026-03.ndjson")
	if err != nil {
		log.Fatalf("log खोलें: %v", err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Buffer(make([]byte, 1024*1024), 1024*1024) // प्रति line 1 MB

	for scanner.Scan() {
		var line LogLine
		if err := json.Unmarshal(scanner.Bytes(), &line); err != nil {
			continue // malformed lines skip करें
		}
		if line.Level == "error" {
			fmt.Printf("%s [%s] %s trace=%s
",
				line.Timestamp, line.Service, line.Message, line.TraceID)
		}
	}
	if err := scanner.Err(); err != nil {
		log.Fatalf("scan: %v", err)
	}
}
नोट:Streaming पर switch करें जब JSON file 100 MB से अधिक हो या unbounded streams process करते समय (Kafka consumers, log pipelines, S3 object reads)। 500 MB JSON file को os.ReadFile से load करने पर उस पूरे buffer को heap पर allocate करेगा, GC pressure trigger करेगा, और memory-constrained containers में OOM cause कर सकता है।

सामान्य गलतियाँ

MarshalIndent से return हुई error को ignore करना

समस्या: _ से error discard करने का मतलब है कि non-serializable value (channel, function, complex number) चुपचाप nil output produce करती है या downstream string(nil) call करने पर panic करती है।

समाधान: हमेशा error check करें। अगर आप ऐसे type को marshal कर रहे हैं जो हमेशा succeed करनी चाहिए, तो silent data loss से बेहतर है panicking log.Fatalf।

Before · Go
After · Go
data, _ := json.MarshalIndent(payload, "", "  ")
fmt.Println(string(data)) // marshal fail होने पर empty string
data, err := json.MarshalIndent(payload, "", "  ")
if err != nil {
    log.Fatalf("marshal payload: %v", err)
}
fmt.Println(string(data))
Binary output के लिए os.Stdout.Write की बजाय fmt.Println use करना

समस्या: fmt.Println(string(data)) JSON के बाद newline character append करता है, जो उन pipelines को corrupt करता है जो output को raw bytes के रूप में treat करते हैं — जैसे jq में pipe करना या binary protocol में लिखना।

समाधान: Binary-clean output के लिए os.Stdout.Write(data) use करें। अगर human display के लिए trailing newline चाहिए, तो उसे explicitly append करें।

Before · Go
After · Go
data, _ := json.MarshalIndent(cfg, "", "  ")
fmt.Println(string(data)) // end में extra newline जोड़ता है
data, _ := json.MarshalIndent(cfg, "", "  ")
os.Stdout.Write(data)
os.Stdout.Write([]byte("
")) // केवल ज़रूरत पड़ने पर explicit newline
Pointer fields पर omitempty भूलना

समस्या: omitempty के बिना, nil *string या *int pointer "field": null के रूप में serialize होता है। यह internal field names expose करता है और consumer side पर strict JSON schema validators को break कर सकता है।

समाधान: उन pointer fields में omitempty जोड़ें जो आप output में absent (null नहीं) चाहते हैं। omitempty के साथ nil *T JSON में कोई key नहीं बनाती।

Before · Go
After · Go
type WebhookPayload struct {
    EventID   string  `json:"event_id"`
    ErrorMsg  *string `json:"error_msg"`  // nil होने पर null के रूप में दिखता है
}
// {"event_id":"evt_3c7f","error_msg":null}
type WebhookPayload struct {
    EventID   string  `json:"event_id"`
    ErrorMsg  *string `json:"error_msg,omitempty"`  // nil होने पर omit
}
// {"event_id":"evt_3c7f"}
Structs की बजाय map[string]interface{} use करना

समस्या: map[string]any में unmarshal करने से type information खो जाती है, manual type assertions चाहिए, और non-deterministic key order produce होती है — JSON diffs और log comparisons को कठिन बनाता है।

समाधान: Proper json tags के साथ struct define करें। Structs type-safe हैं, faster marshal होते हैं, struct definition से match करते deterministic field order produce करते हैं, और code को self-documenting बनाते हैं।

Before · Go
After · Go
var result map[string]any
json.Unmarshal(body, &result)
port := result["port"].(float64) // type assertion ज़रूरी, गलत type पर panic
type ServiceStatus struct {
    Service string `json:"service"`
    Port    int    `json:"port"`
    Healthy bool   `json:"healthy"`
}
var result ServiceStatus
json.Unmarshal(body, &result)
port := result.Port // typed, safe, fast

encoding/json बनाम विकल्प — त्वरित तुलना

विधि
सुन्दर आउटपुट
वैध JSON
कस्टम प्रकार
स्ट्रीमिंग
इंस्टॉलेशन चाहिए
json.MarshalIndent
✓ MarshalJSON से
नहीं (stdlib)
json.Indent
लागू नहीं (केवल bytes)
नहीं (stdlib)
json.Encoder
✗ (compact)
✓ MarshalJSON से
नहीं (stdlib)
go-json
go get
sonic
go get (amd64/arm64)
jq (CLI)
लागू नहीं
System install

किसी भी case के लिए json.MarshalIndent use करें जहाँ आप struct definition control करते हैं और formatted output चाहिए — config files, debug logging, test fixtures, और API response logging। तब json.Indent use करें जब आपके पास पहले से raw bytes हों और Go types के माध्यम से round-trip किए बिना केवल whitespace जोड़नी हो। go-json या sonic पर तभी switch करें जब profiling confirm करे कि JSON marshaling measurable bottleneck है — अधिकांश services के लिए, standard library पर्याप्त से अधिक है।

अक्सर पूछे जाने वाले प्रश्न

Go में JSON को pretty print कैसे करें?

encoding/json पैकेज से json.MarshalIndent(v, "", "\t") को call करें — दूसरा argument प्रति-लाइन prefix है (आमतौर पर खाली) और तीसरा प्रति-लेवल indent है। टैब के लिए "\t" या दो spaces के लिए " " पास करें। कोई external library नहीं चाहिए; encoding/json Go standard library के साथ आती है।

Go
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

func main() {
	config := map[string]any{
		"service": "payments-api",
		"port":    8443,
		"region":  "ap-south-1",
	}
	data, err := json.MarshalIndent(config, "", "	")
	if err != nil {
		log.Fatalf("marshal: %v", err)
	}
	fmt.Println(string(data))
	// {
	// 	"port": 8443,
	// 	"region": "ap-south-1",
	// 	"service": "payments-api"
	// }
}

json.Marshal और json.MarshalIndent में क्या अंतर है?

json.Marshal compact single-line JSON बनाता है जिसमें कोई whitespace नहीं होती — network transfer के लिए आदर्श जहाँ हर byte मायने रखती है। json.MarshalIndent दो extra string parameters लेता है (prefix और indent) और इंडेंटेड, human-readable output बनाता है। दोनों functions एक ही value types accept करते हैं और ([]byte, error) return करते हैं। MarshalIndent की एकमात्र cost थोड़े अधिक output bytes और whitespace insert करने के लिए नगण्य CPU है।

Go
import "encoding/json"

type HealthCheck struct {
	Status  string `json:"status"`
	Version string `json:"version"`
	Uptime  int    `json:"uptime_seconds"`
}

h := HealthCheck{Status: "ok", Version: "1.4.2", Uptime: 86400}

compact, _ := json.Marshal(h)
// {"status":"ok","version":"1.4.2","uptime_seconds":86400}

pretty, _ := json.MarshalIndent(h, "", "  ")
// {
//   "status": "ok",
//   "version": "1.4.2",
//   "uptime_seconds": 86400
// }

struct unmarshal किए बिना JSON []byte को कैसे format करें?

json.Indent(&buf, src, "", "\t") का उपयोग करें। यह function मौजूदा JSON के []byte को लेता है और bytes.Buffer में इंडेंटेड version लिखता है — कोई struct definition नहीं, कोई type assertion नहीं, Go types के माध्यम से कोई round-trip नहीं। यह तब सबसे तेज़ विकल्प है जब आपके पास पहले से raw JSON bytes हों, जैसे HTTP response body या database column से।

Go
import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
)

raw := []byte(`{"endpoint":"/api/v2/invoice","page":1,"per_page":50,"total":312}`)

var buf bytes.Buffer
if err := json.Indent(&buf, raw, "", "	"); err != nil {
	log.Fatalf("indent: %v", err)
}
fmt.Println(buf.String())
// {
// 	"endpoint": "/api/v2/invoice",
// 	"page": 1,
// 	"per_page": 50,
// 	"total": 312
// }

json.MarshalIndent error क्यों return करता है?

encoding/json तब error return करता है जब value को JSON के रूप में represent नहीं किया जा सकता। सबसे सामान्य कारण: channel, function, या complex number को marshal करना (इनका JSON equivalent नहीं है); एक struct जो MarshalJSON() implement करता है और error return करता है; या non-string keys वाला map। महत्वपूर्ण: unexported या nil pointer field वाले struct को marshal करने से error नहीं आती — वे बस छोड़ दिए जाते हैं।

Go
import (
	"encoding/json"
	"fmt"
)

// यह error return करेगा — channels JSON-serializable नहीं हैं
ch := make(chan int)
_, err := json.MarshalIndent(ch, "", "	")
fmt.Println(err)
// json: unsupported type: chan int

// यह ठीक है — omitempty के साथ nil pointer fields चुपचाप छोड़ दिए जाते हैं
type Profile struct {
	ID     string  `json:"id"`
	Avatar *string `json:"avatar,omitempty"`
}
p := Profile{ID: "usr_7b3c"}
data, _ := json.MarshalIndent(p, "", "  ")
// {"id": "usr_7b3c"}  — avatar छोड़ा गया, कोई error नहीं

Go में JSON output से field को कैसे exclude करें?

तीन तरीके हैं। पहला, json:"-" struct tag का उपयोग करें — field हमेशा उसकी value चाहे जो हो, exclude होती है। दूसरा, omitempty का उपयोग करें — field तभी exclude होती है जब वह अपने type की zero value रखती हो (nil pointer, empty string, 0, false)। तीसरा, unexported (lowercase) fields को encoding/json किसी भी tag के बिना automatically exclude करता है।

Go
type PaymentMethod struct {
	ID           string  `json:"id"`
	Last4        string  `json:"last4"`
	ExpiryMonth  int     `json:"expiry_month"`
	ExpiryYear   int     `json:"expiry_year"`
	CVV          string  `json:"-"`                    // हमेशा exclude
	BillingName  string  `json:"billing_name,omitempty"` // खाली होने पर exclude
	internalRef  string                                 // unexported — auto exclude
}

pm := PaymentMethod{
	ID: "pm_9f3a", Last4: "4242",
	ExpiryMonth: 12, ExpiryYear: 2028,
	CVV: "123", internalRef: "stripe:pm_9f3a",
}
data, _ := json.MarshalIndent(pm, "", "  ")
// CVV, BillingName (खाली), और internalRef output में नहीं दिखते

JSON marshaling में time.Time को कैसे handle करें?

encoding/json डिफ़ॉल्ट रूप से time.Time को RFC3339Nano format में marshal करता है (जैसे "2026-03-10T14:22:00Z"), जो ISO 8601 compatible है। यदि आपको अलग format चाहिए — जैसे legacy API के लिए Unix epoch integers, या custom date-only string — time.Time embed करने वाले wrapper type पर MarshalJSON() implement करें।

Go
import (
	"encoding/json"
	"fmt"
	"time"
)

// Default behavior — RFC3339Nano, कोई custom code नहीं चाहिए
type AuditEvent struct {
	Action    string    `json:"action"`
	OccurredAt time.Time `json:"occurred_at"`
}

e := AuditEvent{
	Action:    "invoice.paid",
	OccurredAt: time.Date(2026, 3, 10, 14, 22, 0, 0, time.UTC),
}
data, _ := json.MarshalIndent(e, "", "  ")
// {
//   "action": "invoice.paid",
//   "occurred_at": "2026-03-10T14:22:00Z"
// }

// Custom: Unix timestamp integer के रूप में
type UnixTime struct{ time.Time }

func (u UnixTime) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("%d", u.Unix())), nil
}

संबंधित टूल्स

इसमें भी उपलब्ध:PythonJavaScriptBash
JO
James OkaforSystems Engineer

James is a systems engineer and Go enthusiast who focuses on high-performance microservices, command-line tooling, and infrastructure automation. He enjoys the simplicity and explicitness of Go and writes about building fast, reliable backend systems. When not coding he explores distributed systems concepts and contributes to open-source Go libraries.

TM
Tobias Müllerतकनीकी समीक्षक

Tobias is a platform engineer who builds developer tooling and internal infrastructure in Go. He has authored several open-source CLI tools and contributes to the Go toolchain ecosystem. He writes about the cobra and urfave/cli frameworks, cross-platform binary distribution, configuration management, and the patterns that make Go an ideal language for building reliable, self-contained command-line utilities.