0
0
GoHow-ToBeginner · 3 min read

How to Use json.RawMessage in Go: Simple Guide

In Go, json.RawMessage is a type that holds raw JSON bytes and allows you to delay or customize JSON decoding. You use it by declaring a field of type json.RawMessage in your struct, which stores the raw JSON data as bytes without decoding it immediately.
📐

Syntax

The json.RawMessage type is a slice of bytes ([]byte) that stores raw JSON data. You typically use it as a field type in a struct to hold JSON data without decoding it immediately.

Example syntax:

type MyStruct struct {
    Raw json.RawMessage `json:"raw"`
}

Here, Raw will hold the raw JSON bytes from the raw field in the JSON input.

go
type MyStruct struct {
    Raw json.RawMessage `json:"raw"`
}
💻

Example

This example shows how to use json.RawMessage to store raw JSON data and decode it later.

go
package main

import (
    "encoding/json"
    "fmt"
)

type Message struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    jsonStr := `{"type":"user","data":{"name":"Alice","age":30}}`

    var msg Message
    err := json.Unmarshal([]byte(jsonStr), &msg)
    if err != nil {
        panic(err)
    }

    fmt.Println("Message Type:", msg.Type)
    fmt.Println("Raw Data:", string(msg.Data))

    // Decode the raw JSON data later
    var user User
    err = json.Unmarshal(msg.Data, &user)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Decoded User: %+v\n", user)
}
Output
Message Type: user Raw Data: {"name":"Alice","age":30} Decoded User: {Name:Alice Age:30}
⚠️

Common Pitfalls

  • Not decoding json.RawMessage explicitly: It holds raw bytes, so you must unmarshal it separately to get structured data.
  • Assuming it is a string: It is a byte slice, so convert to string only for printing or debugging.
  • Modifying raw bytes carelessly: Changing the raw bytes without proper JSON format can cause errors during decoding.
go
package main

import (
    "encoding/json"
    "fmt"
)

type Msg struct {
    Data json.RawMessage `json:"data"`
}

func main() {
    jsonStr := `{"data":{"name":"Bob"}}`

    var m Msg
    json.Unmarshal([]byte(jsonStr), &m)

    // Wrong: treating RawMessage as string data directly
    fmt.Println("Wrong print:", m.Data) // prints bytes

    // Right: convert to string for display
    fmt.Println("Correct print:", string(m.Data))

    // Right: decode RawMessage to struct
    var user struct { Name string `json:"name"` }
    json.Unmarshal(m.Data, &user)
    fmt.Println("Decoded name:", user.Name)
}
Output
Wrong print: [123 34 110 97 109 101 34 58 34 66 111 98 34 125] Correct print: {"name":"Bob"} Decoded name: Bob
📊

Quick Reference

  • json.RawMessage stores raw JSON bytes without decoding.
  • Use it to delay decoding or handle unknown JSON structures.
  • Always unmarshal RawMessage separately to get usable data.
  • Convert to string only for printing or debugging.

Key Takeaways

Use json.RawMessage to hold raw JSON bytes and delay decoding.
Always unmarshal json.RawMessage separately to convert raw bytes into structured data.
Do not treat json.RawMessage as a string; convert it explicitly when needed.
json.RawMessage is useful for handling dynamic or unknown JSON fields.
Modifying raw JSON bytes requires care to maintain valid JSON format.