'gin/golang gin-gonic does not parse time.Time properly for unix json?
I cannot find the way to execute this code properly with UNIX:
package main
import (
"time"
"github.com/gin-gonic/gin"
"net/http"
)
type Things struct {
Name string `json:"name"`
OneDay time.Time `json:"oneDay"`
}
type Example struct {
Things []Things `json:"things"`
Something int `json:"something"`
}
func TestGinGo(c *gin.Context) {
var example Example
c.BindJSON(&example)
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/", TestGinGo)
r.Run("0.0.0.0:8080")
}
I call this endpoint like this:
curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
"things": [{
"name": "bling",
"oneDay": "2020-01-01T00:00:00Z"
}],
"something": 2
}'
The response is correct:
{
"data": {
"things": [
{
"name": "bling",
"oneDay": "2020-01-01T00:00:00Z"
}
],
"something": 2
}
}
Now I change slightly the code to work with UNIX like this:
package main
import (
"time"
"github.com/gin-gonic/gin"
"net/http"
)
type Things struct {
Name string `json:"name"`
OneDay time.Time `json:"oneDay" time_format:"unix"`
}
type Example struct {
Things []Things `json:"things"`
Something int `json:"something"`
}
func TestGinGo(c *gin.Context) {
var example Example
c.BindJSON(&example)
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/", TestGinGo)
r.Run("0.0.0.0:8080")
}
And I call it like this:
curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
"things": [{
"name": "bling",
"oneDay": 1589898758007
}],
"something": 2
}'
And I get this error now (400 bad format):
{"data":{"things":[{"name":"bling","oneDay":"0001-01-01T00:00:00Z"}],"something":0}}
I get into the library... and I see that the code is there to use "unix":
https://github.com/gin-gonic/gin/blob/master/binding/form_mapping.go#L272
I would really like to use unix, because many languages don't need a library for using unix, and I don't want to force an specific format to be used by consumer... And I don't see where I am missing the ball here...
Solution 1:[1]
time_format
tag is only used inform
binding, notjson
;- You can use custom Marshal and Unmarshal functions (see https://pkg.go.dev/encoding/json#example-package-CustomMarshalJSON)
package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
type myTime time.Time
func (mt *myTime) UnmarshalJSON(bs []byte) error {
var timestamp int64
err := json.Unmarshal(bs, ×tamp)
if err != nil {
return err
}
*mt = myTime(time.Unix(timestamp/1000, timestamp%1000*1e6))
return nil
}
func (mt myTime) MarshalJSON() ([]byte, error) {
timestamp := time.Time(mt).UnixNano() / 1e6
log.Println(time.Time(mt).UnixNano())
return json.Marshal(timestamp)
}
type Timestamp struct {
OneDay myTime `json:"oneDay" form:"oneDay"`
AnotherDay time.Time `json:"anotherDay" form:"anotherDay" time_format:"unix"`
}
func parseTime(c *gin.Context) {
var example Timestamp
if err := c.Bind(&example); err != nil {
log.Printf("bind timestamp error: %s", err)
}
c.JSON(http.StatusOK, gin.H{"data": example})
}
func main() {
r := gin.Default()
r.POST("/time", parseTime)
r.Run("0.0.0.0:8080")
}
- send as json
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/json' \
--data '{
"oneDay": 1589898758007,
"anotherDay": "1589898758"
}'
oneDay
is right, anotherDay
doesn't work
{"data":{"oneDay":1589898758007,"anotherDay":"0001-01-01T00:00:00Z"}}
- send as form
curl --location --request POST 'localhost:8080/time' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'oneDay=1589898758007&anotherDay=1589898758'
both are right
{"data":{"oneDay":1589898758007,"anotherDay":"2020-05-19T22:32:38+08:00"}}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |