Skip to content

Instantly share code, notes, and snippets.

@augier
Last active July 30, 2020 15:17
Show Gist options
  • Select an option

  • Save augier/10d08afa536e0a30404b884b6593ede2 to your computer and use it in GitHub Desktop.

Select an option

Save augier/10d08afa536e0a30404b884b6593ede2 to your computer and use it in GitHub Desktop.
An example of unmarshalling inconsistent data in golang
package main
import (
"encoding/json"
"log"
"strconv"
)
func main() {
//unmarshalIdealData()
// unmarshalRealWorldData()
// unmarshalBoth()
}
// In an ideal world all data is consistent. idealData is an example of some
// json (it represents an event)
var idealData = []byte(`
{
"name": "event name",
"id": 1
}
`)
// IdealEvent is a struct that we can use to unmarshal the data into for using
// in bookie
type IdealEvent struct {
Name string `json:"name"`
ID int `json:"id"`
}
// unmarshalIdealData unmarshals some data in an ideal world
func unmarshalIdealData() {
var event IdealEvent
err := json.Unmarshal(idealData, &event)
log.Println(err)
log.Println(event)
}
// In the real world, this aren't always quite so simple. Sometimes things come
// in an incorrect format
var realWorldData = []byte(`
{
"name": "event name",
"id": "1"
}
`)
// unmarshalRealWorldData unmarshals some incorrectly formatted data.
func unmarshalRealWorldData() {
var event IdealEvent
err := json.Unmarshal(realWorldData, &event)
log.Println(err)
log.Println(event)
}
// in golang you can define a new type to handle this
type intSometimesString int
// RealWorldEvent represents an event that we often see delivered from a feed
// where the id is often delivered as an int or a string, for example:
type RealWorldEvent struct {
Name string `json:"name"`
ID intSometimesString `json:"id"`
}
// UnmarshalJSON is a custom unmarshaller for the intSometimesString type
func (ri *intSometimesString) UnmarshalJSON(buf []byte) (err error) {
var i int
var s string
// Check to see if string - if it is, unmarshal and convert to an integer
if buf[0] == '"' {
if err = json.Unmarshal(buf, &s); err != nil {
return err
}
if s == "" {
s = "0"
}
if i, err = strconv.Atoi(s); err != nil {
return err
}
} else {
// otherwise we expect it is an integer
if err = json.Unmarshal(buf, &i); err != nil {
return err
}
}
*ri = intSometimesString(i)
return nil
}
func unmarshalBoth() {
var event RealWorldEvent
err := json.Unmarshal(realWorldData, &event)
log.Println(err)
log.Println(event)
err = json.Unmarshal(idealData, &event)
log.Println(err)
log.Println(event)
}
@shvydok
Copy link

shvydok commented Jul 30, 2020

Thanks a lot, this is really useful example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment