encoding/json.RawMessage în Go

Un fragment JSON păstrat ca text brut: decodarea lui se amână (ex. după un câmp „tip”) sau se trimite mai departe neschimbat.

Sintaxă
type RawMessage []byte

Ce face encoding/json.RawMessage

Un câmp de tip json.RawMessage nu este decodat de Unmarshal: primește textul JSON exact al valorii, ca []byte. La Marshal, textul este pus în rezultat așa cum este.

Cazul tipic: mesaje cu formă variabilă, de exemplu {"tip": "plata", "date": {...}}, unde forma lui date depinde de tip. Citești întâi învelișul cu Date json.RawMessage, te uiți la Tip, apoi faci un al doilea Unmarshal pe Date în structura potrivită. Este util și când doar transmiți mai departe un fragment pe care nu trebuie să-l înțelegi.

Ce returnează

Este un tip; se folosește pentru câmpuri și variabile.

Exemple

Exemplul 1: Mesaje cu tipuri diferite

package main

import (
	"encoding/json"
	"fmt"
)

type Mesaj struct {
	Tip  string          `json:"tip"`
	Date json.RawMessage `json:"date"`
}

type Plata struct {
	Suma   float64 `json:"suma"`
	Moneda string  `json:"moneda"`
}

type Livrare struct {
	Curier string `json:"curier"`
	AWB    string `json:"awb"`
}

func main() {
	flux := []string{
		`{"tip":"plata","date":{"suma":249.9,"moneda":"RON"}}`,
		`{"tip":"livrare","date":{"curier":"FAN","awb":"2026101900123"}}`,
	}
	for _, text := range flux {
		var m Mesaj
		if err := json.Unmarshal([]byte(text), &m); err != nil {
			fmt.Println(err)
			continue
		}
		fmt.Printf("tip=%s, date brute=%s\n", m.Tip, m.Date)
		switch m.Tip {
		case "plata":
			var p Plata
			json.Unmarshal(m.Date, &p)
			fmt.Printf("  plată de %.2f %s\n", p.Suma, p.Moneda)
		case "livrare":
			var l Livrare
			json.Unmarshal(m.Date, &l)
			fmt.Printf("  colet %s prin %s\n", l.AWB, l.Curier)
		}
	}
}

Rezultat

tip=plata, date brute={"suma":249.9,"moneda":"RON"}
  plată de 249.90 RON
tip=livrare, date brute={"curier":"FAN","awb":"2026101900123"}
  colet 2026101900123 prin FAN

Exemplul 2: Fragment trimis mai departe neschimbat

package main

import (
	"encoding/json"
	"fmt"
)

type Raspuns struct {
	Status string          `json:"status"`
	Sursa  string          `json:"sursa"`
	Date   json.RawMessage `json:"date"`
}

func main() {
	deLaFurnizor := json.RawMessage(`{"temp": 14.5, "umiditate": 71, "alerte": []}`)
	r := Raspuns{Status: "ok", Sursa: "meteo-extern", Date: deLaFurnizor}
	out, _ := json.Marshal(r)
	fmt.Println(string(out))
}

Rezultat

{"status":"ok","sursa":"meteo-extern","date":{"temp":14.5,"umiditate":71,"alerte":[]}}

Greșeli frecvente

  • Pui într-un RawMessage text care nu este JSON valid și apoi faci Marshal: rezultă eroare. Verifică cu json.Valid dacă textul vine din altă parte.

Comenzi înrudite

  • encoding/json.Unmarshal: Citește JSON și completează o valoare Go (structură, map, slice) dată prin pointer; potrivește cheile după etichetele json.
  • encoding/json.Marshal: Transformă o valoare Go (structură, map, slice) în JSON compact; etichetele json:”…” aleg numele și regulile câmpurilor.
  • encoding/json.Marshaler: Interfețe pentru a controla singur forma JSON a unui tip: MarshalJSON la scriere, UnmarshalJSON la citire.