0

I have a Gin-Gonic REST API in Golang. Here I am trying to output users that are already registered as JSON, currently in Postman I only get that:

(You can ignore the lastRequest-Attribut, because it is currently always nil)

"[{\"id\":\"e61b3ff8-6cdf-4b23-97a5-a28107c57543\",\"firstname\":\"John\",\"lastname\":\"Doe\",\"email\":\"john@doe.com\",\"username\":\"johndoe\",\"token\":\"19b33c79-32cc-4063-9381-f2b64161ad8a\",\"lastRequest\":null},

But I want it like this:

[{
        "id": "e61b3ff8-6cdf-4b23-97a5-a28107c57543",
        "username": "johndoe",
        "email": "john@doe.com",
        "token": "19b33c79-32cc-4063-9381-f2b64161ad8a",
        "lastRequest": null
    }]

How do I manage this, I tried many things with the 'json.MarshalIndent' (from this stackoverflow-post), however it didn't change anything for me, what do I need to do? Because the backslashes stay no matter what I do, at most \t or spaces are inserted. I have also read that I have to do it as a byte array, but that didn't work for me either (maybe I did something wrong here too).

Here my current code:


var users []User
r.GET("/getusers", func(c *gin.Context) {
    usersArr := make([]User, len(users))
    for i := 0; i < len(users); i++ {
        usersArr[i] = users[i]
    }
        
    userJson, err := json.Marshal(testUser)
    if err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
    } else {
        c.JSON(200, string(userJson))
    }
})

type User struct {
    Id          string        `json:"id"`
    Firstname   string        `json:"firstname"`
    Lastname    string        `json:"lastname"`
    Email       string        `json:"email"`
    Username    string        `json:"username"`
    Token       string        `json:"token"`
    LastRequest []lastRequest `json:"lastRequest"`
}

3 Answers3

1

Two things:

  1. The "backslashes" are just escape characters. They aren't literally there.
  2. Indenting JSON is a simple matter of calling the appropriate Indent function:

If you have the JSON string already, use the json.Indent function from the encoding/json package:

input := []byte("[{\"id\":\"e61b3ff8-6cdf-4b23-97a5-a28107c57543\",\"firstname\":\"John\",\"lastname\":\"Doe\",\"email\":\"john@doe.com\",\"username\":\"johndoe\",\"token\":\"19b33c79-32cc-4063-9381-f2b64161ad8a\",\"lastRequest\":null}]")
buf := &bytes.Buffer{}
if err := json.Indent(buf, input, "", "\t"); err != nil {
    panic(err)
}
fmt.Println(buf.String())

Playground link

However, if you're trying to marshal directly into the indented form, just use the MarshalIndent function intead of Marshal:

    userJson, err := json.MarshalIndent(testUser, "", "\t")
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Thanks for the reply, I have tested both options but it does not work for me. Option 1 ```usersArr := make([]User, len(users)) userJson, err := json.Marshal(usersArr) buf := &bytes.Buffer{} if err := json.Indent(buf, userJson, "", "\t"); err != nil { // err } else { c.JSON(200, buf.String()) }``` Option 2 ```usersArr := make([]User, len(users)) userJson2, err := json.MarshalIndent(usersArr, "", "\t") if err != nil { // err } else { c.JSON(200, string(userJson2)) }``` Result 1 + 2 `"[\n\t{\n\t\t\"id\": \"db848d0e-8f7f-434f-bf6d-fd9085c9c86f\ ...` – anonymoushuman Apr 18 '22 at 08:38
  • In the console the JSON is formatted pretty, but in postman there is the same problem. ```userJson, err := json.Marshal(usersArr) input := []byte(userJson) if err != nil { c.JSON(400, gin.H{"error-name": "userArray is empty (nil)", "error-message": err.Error()}) } else { buf := &bytes.Buffer{} if err := json.Indent(buf, input, "", "\t"); err != nil { c.JSON(400, gin.H{"error": err.Error()}) } c.JSON(200, buf.String()) fmt.Println(buf.String()) }``` – anonymoushuman Apr 18 '22 at 08:44
  • That shows that it is working. The `\t` characters are tabs. – Jonathan Hall Apr 18 '22 at 10:53
  • But why is it not formatted when I make a request with postman or curl? It is only formatted when it is directly output to the console, but I would need it in the request. – anonymoushuman Apr 18 '22 at 10:56
0

Well this would be my first answer in stackoverflow, hope this helps.

Go gin framework comes with a few handy functions, since I've got no idea what version of golang nor Gin Framework you're using you could try this:

var users []User
r.GET("/getusers", func(c *gin.Context) {
    usersArr := make([]User, len(users))
    for i := 0; i < len(users); i++ {
        usersArr[i] = users[i]
    }
        
    if err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
    } else {
        c.JSON(200, users)
// If Indentation is required you could try:
        c.IndentedJSON(200, users)
    }
})

type User struct {
    Id          string        `json:"id"`
    Firstname   string        `json:"firstname"`
    Lastname    string        `json:"lastname"`
    Email       string        `json:"email"`
    Username    string        `json:"username"`
    Token       string        `json:"token"`
    LastRequest []lastRequest `json:"lastRequest"`
}
0

Hope this function helps.

import (
"encoding/json"
"strings"
)

func logRequest(log *logrus.Entry, data []byte) {
        cp := bytes.NewBuffer([]byte{})
        if err := json.Compact(cp, data); err == nil {
            log.Info("Request received: ", string(cp.Bytes()))
        } else {
            stringifiedData := strings.Replace(string(data[:]), "\n", "", -1)
            stringifiedData = strings.Replace(stringifiedData, "\r\n", "", -1)
            stringifiedData = strings.Replace(stringifiedData, "\t", "", -1)
            log.Info("Request received: ", strings.ReplaceAll(stringifiedData, " ", ""))
        }
    }
Bush
  • 261
  • 1
  • 11