Reputation: 3070
I am trying to obtain an HTTP request body which is a json object and decode it into a Go struct I have defined.
Two of the fields of the struct is of time.Time
type. While having only one such typed field everything works correctly.
If I have more than one time.Time
typed fields in the go struct I cannot decode it and get the error:
2014/11/01 01:07:04 parsing time "null" as ""2006-01-02T15:04:05Z07:00"": cannot parse "null" as """
The problem is in the decoding lines. Despite my debugging efforts I could have reached a meaningful result. That issue seems strange which is actually should not be.
What am I missing here?
func register(w http.ResponseWriter, r *http.Request){
//Read Request Body JSON Into Go Types
var requestBody = []byte(`{"username":"qwewwwqweqwe","password":"can","usertype":"student","firstname":"","midname":null,"surname":null,"signuptimestamp":null,"userstatus":null,"phone":null,"email":null,"address":null,"city":null,"country":null,"language":null,"lastlogintimestamp":null}`)
type RegisterStructure struct {
Id int `json:"id"`
Timestamp time.Time `json:"timestamp,omitemty"`
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
Username string `json:"username"`
Password string `json:"password"`
UserType string `json:"usertype"`
FirstName string `json:"firstname"`
Midname string `json:"midname"`
Surname string `json:"surname"`
UserStatus string `json:"userstatus"`
Phone string `json:"phone"`
Email string `json:"email"`
Address string `json:"address"`
City string `json:"city"`
Country string `json:"country"`
Language string `json:"language"`
//LastLoginTimestamp time.Time `json:"lastlogintimestamp,omitempty"`
}
var registerInstance RegisterStructure
var now = time.Now()
fmt.Printf("now is %v", now)
fmt.Println()
fmt.Printf("1 registerInstance after inited here is %v", registerInstance)
fmt.Println()
registerInstance = RegisterStructure{Timestamp: now, SignupTimestamp: now,}
fmt.Printf("registerInstance after set to var now here is %v", registerInstance)
fmt.Println()
dec := json.NewDecoder(bytes.NewReader(requestBody))
err = dec.Decode(®isterInstance)
if err != nil {
fmt.Printf("error happens here.")
log.Fatal(err)
}
Upvotes: 4
Views: 3779
Reputation: 12013
Ok. Here is a reproducible example that demonstrates the error you're seeing.
package main
import (
"encoding/json"
"fmt"
"bytes"
"time"
)
type RegisterStructure struct {
SignupTimestamp time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBody := []byte(`{"signuptimestamp" : null}`)
dec := json.NewDecoder(bytes.NewReader(requestBody))
registerInstance := RegisterStructure{}
err := dec.Decode(®isterInstance)
if err != nil {
fmt.Println(err)
}
}
The error you're seeing has nothing to do with having multiple timestamps. This is why showing inputs is critical for debugging situations like this, and why you should go back and change your question to include a sample requestBody
as part of the question content. Otherwise, it becomes very difficult to guess what you're doing.
What's happening is that null
is not handled by the JSON unmarshaller for time.Time
. The documentation for time.Time's unmarshaller says: UnmarshalJSON implements the json.Unmarshaler interface. The time is expected to be a quoted string in RFC 3339 format.
null
is not such a value: the decoder in this case will not try to construct a "zero" value for the timestamp.
What you want to do is change the type of SignupTimestamp
from time.Time
to *time.Time
, so that the null
value can be explicitly represented as a nil
pointer.
Here is an example to demonstrate:
package main
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
type RegisterStructure struct {
SignupTimestamp *time.Time `json:"signuptimestamp,omitempty"`
}
func main() {
requestBodies := []string{
`{"signuptimestamp" : "1985-04-12T23:20:50.52Z"}`,
`{"signuptimestamp" : null}`,
}
for _, requestBody := range requestBodies {
dec := json.NewDecoder(bytes.NewReader([]byte(requestBody)))
registerInstance := RegisterStructure{}
err := dec.Decode(®isterInstance)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v\n", registerInstance)
}
}
Upvotes: 7