V
V
veryoriginalnickname2021-10-04 21:33:39
go
veryoriginalnickname, 2021-10-04 21:33:39

How to avoid escape on json marshal?

there is a template for responses in the form of JSON

type ResponseContent struct {
  Meta struct { // тут pagination
    PerPage int    `json:"per_page"`
    Next    string `json:"next"`
  } `json:"meta"`
  Content interface{} `json:"content"` // тут уже основной контент
}

there is also an Article model:
type ModelArticle struct {
  ID          string `json:"id" db:"id"`
  UserID      string `json:"userID" db:"user_id"`
  IsPublished bool   `json:"isPublished" db:"is_published"`
  Title       string `json:"title" db:"title"`
  Content     string `json:"content" db:"content"` // после получения записи из БД тут будет лежать json
  Slug        string     `json:"slug" db:"slug"`
  PublishedAt *time.Time `json:"publishedAt" db:"published_at"`
  CreatedAt   time.Time  `json:"createdAt" db:"created_at"`
  UpdatedAt   time.Time  `json:"updatedAt" db:"updated_at"`
}


for example, now I want to send a list of articles to the user, I do this (a piece of code from the controller):
var responseContent = ResponseContent{Content: articles}
  responseContent.Meta.PerPage = articlesPageSize
  if len(articles) >= articlesPageSize {
    var lastElement = len(articles) - 1
    responseContent.Meta.Next = articles[lastElement].ID
    articles = articles[:lastElement]
  }
  responseContent.Content = articles // здесь массив с записями ([]ModelArticle)
  jsonResponse, _ := json.Marshal(&responseContent)
  theResponse.Send(string(jsonResponse), 200) // это просто обертка ответа для удобства
  return

And the output is this:
{
    "meta": {
        "per_page": 2,
        "next": "01FH40EW2K7M277MGG4JR2ND6F"
    },
    "content": [
        {
            "id": "01FH414KA9CC1XXSDSQXA2T9P3",
            "userID": "01FH39MVA7P4PGC51JZQ13QTB4",
            "isPublished": false,
            "title": "3153511",
            "content": "{\"time\":1633296731413,\"blocks\":[{\"id\":\"pplIIY15Uu\",\"type\":\"paragraph\",\"data\":{\"text\":\"31315\"}}],\"version\":\"2.22.2\"}",
            "slug": "3153511-01FH414KA9CC1XXSDSQXA2T9P3",
            "publishedAt": null,
            "createdAt": "2021-10-04T00:32:11.465411+03:00",
            "updatedAt": "2021-10-04T00:32:11.516038+03:00"
        }
    ]
}

There is a problem with the content field in the post. It is with escape characters, which are completely off topic. How to get rid of them so that the content field looks normal?
When getting entries into the []ModelArticle array, the content field looks fine.
615b4a0f572ef452586549.png
After json marshal something happens to it.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry Shitskov, 2021-10-04
@veryoriginalnickname

You can change the Content type from string to json.RawMessage.
For example:

type JSON json.RawMessage

func (j *JSON) Scan(value interface{}) error {
  bytes, ok := []byte(value.(string))
  if !ok {
    return errors.New(fmt.Sprint("Failed to unmarshal JSON value:", value))
  }

  result := json.RawMessage{}
  err := json.Unmarshal(bytes, &result)
  *j = JSON(result)
  return err
}

func (j JSON) Value() (driver.Value, error) {
  if len(j) == 0 {
    return nil, nil
  }
  result, err := json.RawMessage(j).MarshalJSON()

  return string(result), err
}

func  (j JSON) MarshalJSON() ([]byte, error) {
  if j == nil {
    return []byte("null"), nil
  }
  return j, nil
}

func (j *JSON) UnmarshalJSON(data []byte) error {
  if j == nil {
    return errors.New("JSON: UnmarshalJSON on nil pointer")
  }
  *j = append((*j)[0:0], data...)
  return nil
}

And use Content JSON type

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question