3

I have written an API with Golang. This API does receive data from other services then it responses to users in type of JSON string. Here is the problems I got.

type message struct {
    Data string `json:"data"`
}

func test(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    data := // Retrieve message that contain backslash
    json.NewEncoder(w).Encode(message{Data: data})
}

` If there is a backslash in data that receive from other API. This API will send the response with double backslashes.

Example.

Received data: "asdasdasd\asdasdasd"

Response data: {"data": "asdasdasd\\asdasdasd"}

I have try to figure this out. Here what I got. All of this will be fine if I try to print out in the screen by using fmt.Println().

I only get problem when I try to send those out put in JSON string. Therefore, is there any way to send those data without double backslashes?

tinthid
  • 43
  • 1
  • 5
  • 3
    Backslash is a special character, it must be escaped, i.e. converted from \ to \\. So the encoder is correct. Why do you want to disable the conversion? – putu Aug 28 '17 at 09:03
  • 1
    If your `data` is already a *valid JSON*, then define the `Data` in `message` struct as `json.RawMessage`. Then in the encoder, define the message as `message{Data: json.RawMessage(data)}` – putu Aug 28 '17 at 09:21
  • 1
    `{"data": "asdasdasd\\asdasdasd"}` is the correct JSON representation of the string `asdasdasd\asdasdasd`… – deceze Aug 29 '17 at 07:30

4 Answers4

1

I asked pretty much the same question a couple days ago, here's the post.

Basically you don't want your Data to be a string but an interface{} instead.

type message struct {
    Data interface{} `json:"data"`
}

I think this may apply to you also. And if you want to go RESTFul and return different types of structs, this is definitely the way to go.

Antoine Thiry
  • 2,362
  • 4
  • 28
  • 42
1

As suggested in the comments, json.RawMessage does the trick.

data := map[string]interface{}{}
data["date"] = json.RawMessage([]byte(`"\/Date(1590105600000)\/"`))

b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)

fmt.Println(b.String())
// {"date":"\/Date(1590105600000)\/"}
The Fool
  • 16,715
  • 5
  • 52
  • 86
0

Golang default render will escape JSON, but if you want to disable it you need to define custom renderer like this:

encoder := json.NewEncoder(w)
encoder.SetEscapeHTML(false)
encoder.Encode(data)
Aji Imawan
  • 11
  • 3
-1

You can create a custom method and replace double backslashes with a single one.
Something like that:

func JSONMarshal(v interface{}, backslashEscape bool) ([]byte, error) {
    b, err := json.Marshal(v)

    if backslashEscape {
        b = bytes.Replace(b, []byte(`\\`), []byte(`\`), -1)
    }
    return b, err
}

The json/encoder packages has also DisableHTMLEscaping, if set to true, default is false, it allows you to escape HTML chars.

tinthid
  • 43
  • 1
  • 5
Tinwor
  • 7,765
  • 6
  • 35
  • 56
  • Thank you for your solution. It works!! But there is some issue you need to fix in this code. You have to use backtick **(`)** instead of double-qoute **(")** – tinthid Aug 28 '17 at 09:39
  • It seem that your fixed version using single-quote, not backtick or grave accent. – tinthid Aug 28 '17 at 09:44
  • Edit my answer by clicking edit link. I'm from smartphone and I'll accept your edit – Tinwor Aug 28 '17 at 09:51