encoding/json.NewEncoder în Go

Creează un Encoder care scrie JSON direct într-un io.Writer (răspuns HTTP, fișier, ecran); Encode scrie o valoare.

Sintaxă
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(v any) error
func (enc *Encoder) SetIndent(prefix, indent string)   // Go 1.7
func (enc *Encoder) SetEscapeHTML(on bool)

Ce face encoding/json.NewEncoder

json.NewEncoder(w) creează un *json.Encoder legat de un io.Writer: os.Stdout, un fișier, un http.ResponseWriter. enc.Encode(v) transformă valoarea în JSON și o scrie imediat, urmată de un rând nou. Nu mai ai nevoie de un []byte intermediar ca la Marshal.

enc.SetIndent("", " ") face ca toate valorile următoare să fie indentate. enc.SetEscapeHTML(false) păstrează <, > și & așa cum sunt (implicit sunt codate ca \u003c…), util când JSON-ul nu ajunge într-o pagină HTML.

Cazul cel mai des întâlnit este răspunsul unui API: w.Header().Set("Content-Type", "application/json"), apoi json.NewEncoder(w).Encode(date). Apelurile repetate de Encode scriu câte o valoare pe rând (formatul JSON Lines / NDJSON).

Parametri

Parametru Descriere
w Destinația: orice io.Writer.

Ce returnează

NewEncoder: un *json.Encoder. Encode: o eroare (la valori care nu pot fi codate sau la scriere).

Exemple

Exemplul 1: JSON direct pe ecran, compact și indentat

package main

import (
	"encoding/json"
	"os"
)

type Eveniment struct {
	Tip  string `json:"tip"`
	Oras string `json:"oras"`
	Loc  int    `json:"locuri"`
}

func main() {
	enc := json.NewEncoder(os.Stdout)
	// JSON Lines: câte un obiect pe rând
	enc.Encode(Eveniment{"concert", "Iași", 1200})
	enc.Encode(Eveniment{"teatru", "Cluj", 350})

	enc.SetIndent("", "  ")
	enc.SetEscapeHTML(false)
	enc.Encode(map[string]string{"titlu": "Rock & Roll <live>"})
}

Rezultat

{"tip":"concert","oras":"Iași","locuri":1200}
{"tip":"teatru","oras":"Cluj","locuri":350}
{
  "titlu": "Rock & Roll <live>"
}

Exemplul 2: Răspunsul unui API JSON

package main

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

type Produs struct {
	ID   int     `json:"id"`
	Nume string  `json:"nume"`
	Pret float64 `json:"pret"`
}

func listaProduse(w http.ResponseWriter, r *http.Request) {
	produse := []Produs{{1, "cafea", 32.5}, {2, "ceai verde", 14}}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if err := json.NewEncoder(w).Encode(produse); err != nil {
		http.Error(w, "eroare internă", http.StatusInternalServerError)
	}
}

func main() {
	rec := httptest.NewRecorder()
	listaProduse(rec, httptest.NewRequest("GET", "/api/produse", nil))
	fmt.Println(rec.Code, rec.Header().Get("Content-Type"))
	fmt.Print(rec.Body.String())
}

Rezultat

200 application/json; charset=utf-8
[{"id":1,"nume":"cafea","pret":32.5},{"id":2,"nume":"ceai verde","pret":14}]

Exemplul 3: Scriere într-un fișier

package main

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

func main() {
	f, err := os.Create("note.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	enc := json.NewEncoder(f)
	enc.SetIndent("", "  ")
	err = enc.Encode(map[string][]int{"Ana": {9, 10}, "Mihai": {7, 8, 10}})
	f.Close()
	if err != nil {
		fmt.Println(err)
		return
	}
	continut, _ := os.ReadFile("note.json")
	fmt.Print(string(continut))
}

Rezultat

{
  "Ana": [
    9,
    10
  ],
  "Mihai": [
    7,
    8,
    10
  ]
}

Greșeli frecvente

  • Setezi antetele sau codul de stare după Encode într-un handler: răspunsul a plecat deja cu 200.
  • Te miri de rândul nou de la final: Encode adaugă mereu \n, spre deosebire de Marshal.

Comenzi înrudite

  • encoding/json.Marshal: Transformă o valoare Go (structură, map, slice) în JSON compact; etichetele json:”…” aleg numele și regulile câmpurilor.
  • encoding/json.NewDecoder: Creează un Decoder care citește JSON dintr-un io.Reader (corpul unei cereri, un fișier); Decode citește o valoare.
  • encoding/json.MarshalIndent: Ca Marshal, dar scrie JSON-ul pe mai multe rânduri, indentat, ușor de citit (fișiere de configurare, afișare).
  • net/http.ResponseWriter: Interfața prin care handler-ul construiește răspunsul: antete (Header), cod de stare (WriteHeader) și corp (Write).