N
N
nurzhannogerbek2019-03-01 09:15:37
go
nurzhannogerbek, 2019-03-01 09:15:37

How to fix problem with UnmarshalJSON and MarshalJSON functions?

Hello comrades! Please help me fix the problem.
There is a table in a PostgreSQL database .

CREATE TABLE SURVEYS(
  SURVEY_ID UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  SURVEY_NAME VARCHAR NOT NULL,
  SURVEY_DESCRIPTION TEXT,
  START_PERIOD TIMESTAMP,
  END_PERIOD TIMESTAMP
);

As you can see, the last 3 fields are optional and can store NULL.
Based on this table, I created a structure in Golang:
type Survey struct {
  ID string `json:"survey_id"`
  Name string `json:"survey_name"`
  Description utils.NullString `json:"survey_description"`
  StartPeriod utils.NullTime `json:"start_period"`
  EndPeriod utils.NullTime `json:"end_period"`
}

In a Golang application, I make a GET request for a specific entry:
http://localhost:8000/api/survey/0cf1cf18-d5fd-474e-a8be-754fbdc89720

I get a strange response:
{
    "survey_id": "0cf1cf18-d5fd-474e-a8be-754fbdc89720",
    "survey_name": "NAME",
    "survey_description": {
        "String": "DESCRIPTION",
        "Valid": true
    },
    "start_period": {
        "Time": "2019-01-01T00:00:00Z",
        "Valid": true
    },
    "end_period": {
        "Time": "0001-01-01T00:00:00Z",
        "Valid": false
    }
}

You need to get the following response:
{
    "survey_id": "0cf1cf18-d5fd-474e-a8be-754fbdc89720",
    "survey_name": "NAME",
    "survey_description": "DESCRIPTION",
    "start_period": "2019-01-01 00:00:00",
    "end_period": null
}

How to properly configure MarshalJSON and MarshalJSON functions?
utils.go:
const layout = "2006-01-02 15:04:05"

type NullTime struct {
  pq.NullTime
}

func (nt *NullTime) Scan(value interface{}) error {
  nt.Time, nt.Valid = value.(time.Time)
  return nil
}

func (nt NullTime) Value() (driver.Value, error) {
  if !nt.Valid {
    return nil, nil
  }
  return nt.Time, nil
}

func (nt *NullTime) MarshalJSON() ([]byte, error) {
  if !nt.Valid {
    return []byte("null"), nil
  }
  val := fmt.Sprintf("\"%s\"", nt.Time.Format(layout))
  return []byte(val), nil
}

func (nt *NullTime) UnmarshalJSON(b []byte) error {
  err := json.Unmarshal(b, &nt.Time)
  nt.Valid = err == nil
  return err
}


type NullString struct {
  sql.NullString
}

func (ns *NullString) MarshalJSON() ([]byte, error) {
  if !ns.Valid {
    return []byte("null"), nil
  }
  return json.Marshal(ns.String)
}

func (ns *NullString) UnmarshalJSON(b []byte) error {
  err := json.Unmarshal(b, &ns.String)
  ns.Valid = err == nil
  return err
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
L
Leonid Nikolaev, 2019-03-01
@nikonor

the simplest option is to stupidly make the second type, where you convert the received one. already make logic in it.

F
falconandy, 2019-03-03
@falconandy

Your structure fields are utils.NullString and utils.NullTime structures, and MarshalJSON is implemented for pointers to these structures. Just remove the * from the MarshalJS signature.
https://stackoverflow.com/questions/39164471/marsh...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question