Json response contains escaped doublequotes

Hi,
Problem description: curl commands returns data with escaped double quotes as below

curl -X GET http://test.com/api/appointment
{"Title":"OK","status":200,"records":2,"data":"[{\"id\":14,\"start\":\"2022-07-03T18:15:00Z\"}]

Expected output is without escaped double quotes
{“Title”:“OK”,“status”:200,“records”:2,“data”:"[{“id”:14,“start”:“2022-07-03T18:15:00Z”}]

Now lets explain program logic.

The requirement is to retrieve database records using gorm and sent back to the client as API response in json format using json.NewEncoder(w).Encode. The below structs are designed for this purpose where ApiResponse struct is used for holding both database query result(“Data”) plus meta data such as title status and records. The appointment struct is the one that holds retrieved database records which will be then later embed in to API response. Since I am using different structs for different database tables, the retrieved database records stored in respective struct will marshalled to bytes, then converts to string. Finally, writes back to http writer.

The below struct used to formulate the API response.

type ApiResponse struct {
Title string json:"Title"
Status uint json:"status"
Records int64 json:"records"
Data string json:"data"
}

The below struct holds the records retrieved from database.
type Appointment struct {

    Id       uint       `json:"id"`
    Name     string    `json:"name"`
    Start    time.Time  `json:"start"`
    ....SKIPPING THE REST....

}

//Appointment is a struct that hold database records retrieved using gorm
//Marshal appointment to []byte to later converted to string.

data, _ := json.Marshal(appointment)

records := string(data)
//Write the response back to the client
json.NewEncoder(w).Encode(ApiResponse{Title: “OK”, Status: http.StatusOK, Records: utils.RowsAffected, Data: records })

It perfectly suits to my needs except the escaped doublequotes like below.

"[{\"id\":14,\"start\":\"2022-07-03T18:15:00Z\"}]

Please help me to find out that one or two line code that does the magic of removing \ from the output optimally.

If the quotes were not escaped the JSON was not valid.

Data is a string, not an array, so each of the quotes within needs to be escaped.

Thanks. But I am looking for a solution to have json string without escaped double quotes. How to achieve that in my case. Is there any way to achieve below json when json.NewEncoder(w).Encode is used.

{“Title”:“OK”,“status”:200,“records”:2,“data”:"[{“id”:14,“start”:“2022-07-03T18:15:00Z”}]

No, as that wouldn’t be valid JSON.

The problem is that your Data property is a string which just happens to contain JSON. So, go is correctly escaping the quotes in that string. Change your struct to contain an array of child structs instead of a string like so:

package main

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

type Appointment struct {
	Id    uint      `json:"id"`
	Name  string    `json:"name"`
	Start time.Time `json:"start"`
}

type ApiResponse struct {
	Title   string        `json:"Title"`
	Status  uint          `json:"status"`
	Records int64         `json:"records"`
	Data    []Appointment `json:"data"`
}

func main() {
	appts := []Appointment{{1, "Apt Name", time.Now()}}
	resp := ApiResponse{Title: "OK", Status: http.StatusOK, Records: 23, Data: appts}
	json.NewEncoder(os.Stdout).Encode(resp)
}

… which yields the following output:

{“Title”:“OK”,“status”:200,“records”:23,“data”:[{“id”:1,“name”:“Apt Name”,“start”:“2009-11-10T23:00:00Z”}]}

Run it yourself in the playground here: Go Playground - The Go Programming Language

1 Like

Again, thanks for your time. But here Data is not a single struct. It is a common container that supposed to hold data of different structs such as customers, appointment, employees. So there is need of flexible data type like string to which those struct needs to be converted just before sending them as API response.

//Struct for Appoinment
type Appointment struct {
Id uint json:"id"
Name string json:"name"
Start time.Time json:"start"
}
//Struct for Customers
type Customers struct {
Id unit json:"id"
Name string json:"name"
Phone string json:"phone"
DOB time json:"dob"
}
//Struct for Employees
type Employee struct {
Id unit json:"id"
Name string json:"name"
Phone string json:"phone"
Designation string json:"designation"
}

Expected API request and responses
curl -X GET http://test.com/api/appointment
{“Title”:“OK”,“status”:200,“records”:1,“data”:"[{“id”:14,“start”:“2022-07-03T18:15:00Z”}]

curl -X GET http://test.com/api/customers
{“Title”:“OK”,“status”:200,“records”:1,“data”:"[{“id”:14,“name”:“John", “Phone”:+810000000", “11-11-11”}]
&
curl request for employees

Although it is possible to define different API responses struct that seems inefficient. Could there be any better implementation?

As you are not using JSON, don’t use the JSON packages. To fulfill your requirements with the not-conforming string, you need to write your own encoder and decoder, also your API consumers need to do the same, as they can not use JSON libraries here.

Either you use some interface type there or you use the stringly taped thing, though then you really should use the properly encoded strings and not something else that makes it look like but not actual valid JSON

1 Like

Hi,
Thanks all for your suggestion and valuable time. I express my full gratitude.
Finally decided to have response container for each requirement like below and ofcource that worked fantastically although that made my code bulky.

type CustomerData struct {

Title   string     `json:"Title"`

Status  uint       `json:"status"`

Records int64      `json:"records"`

Data    []Customer `json:"data"`

}

//Definition for Product Data API response

type ProductData struct {

Title   string    `json:"Title"`

Status  uint      `json:"status"`

Records int64     `json:"records"`

Data    []Product `json:"data"`

}

and so on…

I am gonna mark this topic as closed. Thanks you once again.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.