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:
Encodeadaugă mereu\n, spre deosebire deMarshal.
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).