How can I pretty-print JSON using Go?
Asked Answered
B

16

347

Does anyone know of a simple way to pretty-print JSON output in Go?

I'd like to pretty-print the result of json.Marshal, as well as formatting an existing string of JSON so it's easier to read.

Bullough answered 26/9, 2013 at 20:59 Comment(2)
Warning: on my experiments, in JSON dictionaries the strings indices must be enclosed in parentheses. So, {name: "value"} won't be okay, despite that most Javascript interpreter uses it. Only {"name": "value"} will work with the Go JSON library functions. – Shoveler
@Shoveler I think you're confusing JavaScript literal syntax with JSON proper. The JSON spec (json.org) clearly indicates that only string literals are allowed (meaning it needs quotes), while JS language object syntax does not have that restriction. The Go library is following the spec. – Bullough
C
509

MarshalIndent will allow you to output your JSON with indentation and spacing. For example:

{
    "data": 1234
}

The indent argument specifies the series of characters to indent with. Thus, json.MarshalIndent(data, "", " ") will pretty-print using four spaces for indentation.

Cyrenaica answered 26/9, 2013 at 21:17 Comment(2)
Yeah, that looks like just the thing - it's already built-in, only left is to include the keyword "pretty-print" in the pkg doc so the next guy searching finds it. (Will leave a feedback note for the doc maintainers.) Tks! – Bullough
In case you're trying to print this json to console: MarshalIndent returns a ([]byte, error). Just pass the []byte to string() and print, e.g. j, _ := json.MarshalIndent(data, "", "🐱"); fmt.Println(string(j)) – Charleton
P
195

The accepted answer is great if you have an object you want to turn into JSON. The question also mentions pretty-printing just any JSON string, and that's what I was trying to do. I just wanted to pretty-log some JSON from a POST request (specifically a CSP violation report).

To use MarshalIndent, you would have to Unmarshal that into an object. If you need that, go for it, but I didn't. If you just need to pretty-print a byte array, plain Indent is your friend.

Here's what I ended up with:

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

func HandleCSPViolationRequest(w http.ResponseWriter, req *http.Request) {
    body := App.MustReadBody(req, w)
    if body == nil {
        return
    }

    var prettyJSON bytes.Buffer
    error := json.Indent(&prettyJSON, body, "", "\t")
    if error != nil {
        log.Println("JSON parse error: ", error)
        App.BadRequest(w)
        return
    }

    log.Println("CSP Violation:", string(prettyJSON.Bytes()))
}
Phyliciaphylis answered 14/3, 2015 at 8:26 Comment(3)
Thanks! This was very helpful. Just one minor comment that instead of string(prettyJSON.Bytes()) you can do prettyJSON.String() – Reverberate
Cool, didn't know this exists! Perfect for low-impact debug logging. – Brainbrainard
@Reverberate Good point. Actually, we can just do &prettyJSON, because log or fmt executes prettyJSON.String() internally. – Targe
D
66

For better memory usage, I guess this is better:

var out io.Writer
enc := json.NewEncoder(out)
enc.SetIndent("", "    ")
if err := enc.Encode(data); err != nil {
    panic(err)
}
Dingdong answered 23/2, 2017 at 21:52 Comment(4)
Did SetIndent get added recently? It's essentially unknown to most. – Jollification
@Jollification SetIndent (originally named Indent) was apparently added March 2016 and released in Go 1.7, which was about 3 years after this question was originally asked: github.com/golang/go/commit/… github.com/golang/go/commit/… – Eveevection
Any memory comparisons between this and the usage of json.MarshalIndent(..) ? – Homebrew
@ChenA. this does not really appear needed. Both implementation are pretty clear about their pros and cons. For any object, which has size in memory > the length of the buffer used to stream marshal it, a stream encoder will consume less memory than a non stream-encoder. That last encoder needs to hold both representaton of the same data in memory, the original and its encoded version. – Dingdong
F
38

I was frustrated by the lack of a fast, high quality way to marshal JSON to a colorized string in Go so I wrote my own Marshaller called ColorJSON.

With it, you can easily produce output like this using very little code:

ColorJSON sample output

package main

import (
    "fmt"
    "encoding/json"

    "github.com/TylerBrock/colorjson"
)

func main() {
    str := `{
      "str": "foo",
      "num": 100,
      "bool": false,
      "null": null,
      "array": ["foo", "bar", "baz"],
      "obj": { "a": 1, "b": 2 }
    }`

    var obj map[string]interface{}
    json.Unmarshal([]byte(str), &obj)

    // Make a custom formatter with indent set
    f := colorjson.NewFormatter()
    f.Indent = 4

    // Marshall the Colorized JSON
    s, _ := f.Marshal(obj)
    fmt.Println(string(s))
}

I'm writing the documentation for it now but I was excited to share my solution.

Fortenberry answered 27/5, 2018 at 6:56 Comment(1)
Thank you very much! Very cool package, used it for my commercial needs! – Froma
E
27

Edit Looking back, this is non-idiomatic Go. Small helper functions like this add an extra step of complexity. In general, the Go philosophy prefers to include the 3 simple lines over 1 tricky line.


As @robyoder mentioned, json.Indent is the way to go. Thought I'd add this small prettyprint function:

package main

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

//dont do this, see above edit
func prettyprint(b []byte) ([]byte, error) {
    var out bytes.Buffer
    err := json.Indent(&out, b, "", "  ")
    return out.Bytes(), err
}

func main() {
    b := []byte(`{"hello": "123"}`)
    b, _ = prettyprint(b)
    fmt.Printf("%s", b)
}

https://go-sandbox.com/#/R4LWpkkHIN or http://play.golang.org/p/R4LWpkkHIN

Earthstar answered 16/4, 2015 at 3:36 Comment(0)
O
17

Here's what I use. If it fails to pretty print the JSON it just returns the original string. Useful for printing HTTP responses that should contain JSON.

import (
    "encoding/json"
    "bytes"
)

func jsonPrettyPrint(in string) string {
    var out bytes.Buffer
    err := json.Indent(&out, []byte(in), "", "\t")
    if err != nil {
        return in
    }
    return out.String()
}
Ofeliaofella answered 11/4, 2016 at 9:13 Comment(0)
S
8
package cube

import (
    "encoding/json"
    "fmt"
    "github.com/magiconair/properties/assert"
    "k8s.io/api/rbac/v1beta1"
    v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "testing"
)

func TestRole(t *testing.T)  {
    clusterRoleBind := &v1beta1.ClusterRoleBinding{
        ObjectMeta: v1.ObjectMeta{
            Name: "serviceaccounts-cluster-admin",
        },
        RoleRef: v1beta1.RoleRef{
            APIGroup: "rbac.authorization.k8s.io",
            Kind:     "ClusterRole",
            Name:     "cluster-admin",
        },
        Subjects: []v1beta1.Subject{{
            Kind:     "Group",
            APIGroup: "rbac.authorization.k8s.io",
            Name:     "system:serviceaccounts",
        },
        },
    }
    b, err := json.MarshalIndent(clusterRoleBind, "", "  ")
    assert.Equal(t, nil, err)
    fmt.Println(string(b))
}

How it looks like

Selfexistent answered 5/4, 2020 at 16:27 Comment(0)
K
6

Here is my solution:

import (
    "bytes"
    "encoding/json"
)

const (
    empty = ""
    tab   = "\t"
)

func PrettyJson(data interface{}) (string, error) {
    buffer := new(bytes.Buffer)
    encoder := json.NewEncoder(buffer)
    encoder.SetIndent(empty, tab)

    err := encoder.Encode(data)
    if err != nil {
       return empty, err
    }
    return buffer.String(), nil
}
Koontz answered 4/6, 2017 at 23:55 Comment(0)
D
5
//You can do it with json.MarshalIndent(data, "", "  ")

package main

import(
  "fmt"
  "encoding/json" //Import package
)

//Create struct
type Users struct {
    ID   int
    NAME string
}

//Asign struct
var user []Users
func main() {
 //Append data to variable user
 user = append(user, Users{1, "Saturn Rings"})
 //Use json package the blank spaces are for the indent
 data, _ := json.MarshalIndent(user, "", "  ")
 //Print json formatted
 fmt.Println(string(data))
}
Divisible answered 15/11, 2019 at 21:47 Comment(0)
B
4

Another example with http.ResponseWriter.

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

func main() {
    var w http.ResponseWriter

    type About struct {
        ProgName string
        Version string
    }
    goObj := About{ProgName: "demo", Version: "0.0.0"}
    beautifulJsonByte, err := json.MarshalIndent(goObj, "", "  ")
    if err != nil {
        panic(err)
    }
    _, _ = w.Write(beautifulJsonByte)
}

output

{
  "ProgName": "demo",
  "Version": "0.0.0"
}

Go Playground

Boll answered 13/4, 2021 at 9:45 Comment(0)
R
4

If you want to create a commandline utility to pretty print JSON


package main

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


func main(){

    var out bytes.Buffer

    reader := bufio.NewReader(os.Stdin)
    text, _ := reader.ReadString('\n')

    err := json.Indent(&out, []byte(text), "", "  ")
    if err != nil {
      fmt.Println(err)
    }

    fmt.Println(string(out.Bytes()))
}

echo "{\"boo\":\"moo\"}" | go run main.go 

will produce the following output :

{
  "boo": "moo"
}

feel free to build a binary

go build main.go

and drop it in /usr/local/bin

Rohde answered 24/11, 2021 at 14:33 Comment(0)
V
2

A simple off the shelf pretty printer in Go. One can compile it to a binary through:

go build -o jsonformat jsonformat.go

It reads from standard input, writes to standard output and allow to set indentation:

package main

import (
    "bytes"
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    indent := flag.String("indent", "  ", "indentation string/character for formatter")
    flag.Parse()
    src, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        fmt.Fprintf(os.Stderr, "problem reading: %s", err)
        os.Exit(1)
    }

    dst := &bytes.Buffer{}
    if err := json.Indent(dst, src, "", *indent); err != nil {
        fmt.Fprintf(os.Stderr, "problem formatting: %s", err)
        os.Exit(1)
    }
    if _, err = dst.WriteTo(os.Stdout); err != nil {
        fmt.Fprintf(os.Stderr, "problem writing: %s", err)
        os.Exit(1)
    }
}

It allows to run a bash commands like:

cat myfile | jsonformat | grep "key"
Vagarious answered 25/9, 2018 at 13:49 Comment(0)
I
1

i am sort of new to go, but this is what i gathered up so far:

package srf

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

func WriteDataToFileAsJSON(data interface{}, filedir string) (int, error) {
    //write data as buffer to json encoder
    buffer := new(bytes.Buffer)
    encoder := json.NewEncoder(buffer)
    encoder.SetIndent("", "\t")

    err := encoder.Encode(data)
    if err != nil {
        return 0, err
    }
    file, err := os.OpenFile(filedir, os.O_RDWR|os.O_CREATE, 0755)
    if err != nil {
        return 0, err
    }
    n, err := file.Write(buffer.Bytes())
    if err != nil {
        return 0, err
    }
    return n, nil
}

This is the execution of the function, and just standard

b, _ := json.MarshalIndent(SomeType, "", "\t")

Code:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"

    minerals "./minerals"
    srf "./srf"
)

func main() {

    //array of Test struct
    var SomeType [10]minerals.Test

    //Create 10 units of some random data to write
    for a := 0; a < 10; a++ {
        SomeType[a] = minerals.Test{
            Name:   "Rand",
            Id:     123,
            A:      "desc",
            Num:    999,
            Link:   "somelink",
            People: []string{"John Doe", "Aby Daby"},
        }
    }

    //writes aditional data to existing file, or creates a new file
    n, err := srf.WriteDataToFileAsJSON(SomeType, "test2.json")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("srf printed ", n, " bytes to ", "test2.json")

    //overrides previous file
    b, _ := json.MarshalIndent(SomeType, "", "\t")
    ioutil.WriteFile("test.json", b, 0644)

}
Inversely answered 24/7, 2019 at 23:35 Comment(0)
L
1

Here is a short json-string to json-string conversion example with indent prettyprint without any struct-objects.

    str := `{"a":{"key":"val"}}`
    data := []byte(str)
    empty := []byte{}
    buf := bytes.NewBuffer(empty)
    json.Indent(buf, data, "", "    ")
    readBuf, _ := ioutil.ReadAll(buf)
    fmt.Println((string)(readBuf))
Lyonnaise answered 9/3, 2023 at 17:18 Comment(0)
B
0

Use json.MarshalIndent with string

This easyPrint function accepts argument data (any type of data) to print it into the intended (pretty) JSON format.

import (
  "encoding/json"
  "log"
)

func easyPrint(data interface{}) {
  manifestJson, _ := json.MarshalIndent(data, "", "  ")

  log.Println(string(manifestJson))
}

With name argument.

TODO: make argument name optional.

func easyPrint(data interface{}, name string) {
  manifestJson, _ := json.MarshalIndent(data, "", "  ")

  log.Println(name + " ->", string(manifestJson))
}
Brewster answered 18/4, 2022 at 9:26 Comment(0)
F
0

It might be niche but for those who want to pretty print a JSON string as inline.

- {     "foo": "bar", "buz":    12345        }
+ {"foo":"bar","buz":12345}
- {
- "foo":   "bar",
- "buz":
- 12345 }
+ {"foo":"bar","buz":12345}
func PrettyJSONInline(input []byte) ([]byte, error) {
    var js json.RawMessage

    if err := json.Unmarshal(input, &js); err != nil {
        return nil, errors.New("malformed json")
    }

    // To output pretty with indent use `json.MarshalIndent` instead
    return json.Marshal(js)
}
Finkelstein answered 5/10, 2023 at 9:59 Comment(0)

© 2022 - 2025 β€” McMap. All rights reserved.