Custom time.Time type can not use bindQuery get a value 2
feiyangbeyond opened this issue · comments
I have a new type MyTime
, and it has implements encoding/json.Unmarshaler
.
const defaultTimeLayout = "2006-01-02 15:04:05"
type MyTime time.Time
func (t *MyTime) UnmarshalJSON(data []byte) error {
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
switch value := v.(type) {
case string:
var err error
tt, err := time.ParseInLocation(defaultTimeLayout, value, time.Local)
if err != nil {
return err
}
*t = MyTime(tt)
return nil
default:
return errors.New("invalid time format")
}
}
func (t MyTime) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(t).Format(defaultTimeLayout))
}
And my struct define:
type MyReq struct {
Time MyTime `json:"time" form:"time" binding:"required" time_format:"2006-01-02 15:04:05"`
}
When I use http get query , the same error occurred. And after changing MyReq.Time
type to time.Time
, it works.
I hope it works with MyTime
.
Did I use it improperly?
Originally posted by @feiyangbeyond in #3895 (comment)
--
Why I use MyTime
?
I wish to control the type of time in json serialization/formatting, I use MyTime
in get/post request to keep it consistent
I don't think this issue is about gin, but you can refer to the source code of Time.time and write a custom type of JSON serialization and deserialization method.
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in the RFC 3339 format with sub-second precision.
// If the timestamp cannot be represented as valid RFC 3339
// (e.g., the year is out of range), then an error is reported.
func (t Time) MarshalJSON() ([]byte, error) {
b := make([]byte, 0, len(RFC3339Nano)+len(`""`))
b = append(b, '"')
b, err := t.appendStrictRFC3339(b)
b = append(b, '"')
if err != nil {
return nil, errors.New("Time.MarshalJSON: " + err.Error())
}
return b, nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time must be a quoted string in the RFC 3339 format.
func (t *Time) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}
// TODO(https://go.dev/issue/47353): Properly unescape a JSON string.
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
return errors.New("Time.UnmarshalJSON: input is not a JSON string")
}
data = data[len(`"`) : len(data)-len(`"`)]
var err error
*t, err = parseStrictRFC3339(data)
return err
}
I'm not sure if it's a gin error. Let me tell you the results of the investigation.
The program has thrown an error before it reaches the custom time type I wrote.
This error only occurs when making a get request and using gin to bind query. The error is invalid character '-' after top-level value
My struct:
type Foo struct {
Bar string `form:"bar"`
Time MyTime `form:"time"` // use MyTime
}
When I send get request like /foo?bar=some&time=2024-04-17 13:21:45 , gin uses json.Unmarshal to convert 2024-04-17 13:21:45
to MyTime
,
Since 2024-04-17 13:21:45
is not a normal json string, using json.Unmarshal will definitely report an error.
I think the error root cause is binding single parameter value as json when binding parameters on get request.
I can add "" before and after the time field when sending a get request, this way you can avoid this error.