In a previous article, I was discussing appending JSON data in Go and playing a bit around. I would like to expand on it here a little bit more as I kept working on that.
I did some research around marshalling which is the process to export a slice of bytes to a structure, here a JSON structure. The process of formatting your slice of bytes into a structure is called unmarshalling and the opposite marshalling. For that, your programming language is going to parse the input and build it into the desired output.
Unmarshalling is actually the most interesting as Go is parsing every byte and recognizing limiters characters such as quotes (""), colons (:) or brackets ({}) and of course spaces. Each of those characters will define a condition in the process and expect something.
So for example: you have "
then your program will expect a string and so on.
As Go is a strongly typed language, you must prepare the receiving end for the unmarshalled structure namely, the exact JSON structure.
Here you have the structure of a cURL
on the API of Ergast (a motorsport API) for races:
MRDATA {
RaceTable {
Races [
{
season
round
url
raceName
date
time
Circuit {
},
Results : [
number,
position,
points,
Driver {}
Constructor {}
grid
laps
status
Time {
millis
time
},
FastestLap {
rank
lap
Time {
time
},
AverageSpeed {
units
speed
},
},
],
},
],
},
}
The whole result is embedded in the MRData object, so it means that your Go program receiving this will have to mimic this all work. It can be a bit tedious especially with larger API.
So our code to get it would look like:
// Location represents the details of a circuit.
type Location struct {
Country string `json:"country"`
Latitude string `json:"lat"`
Locatlity string `json:"locality"`
Longitude string `json:"long"`
}
// Circuit represents the details of a circuit.
type Circuit struct {
CircuitID string `json:"circuitID"`
URL string `json:"url"`
Name string `json:"circuitName"`
Location Location `json:"Location"`
}
// Race represents the details of a race.
type Race struct {
Season string `json:"season"`
Round string `json:"round"`
RaceName string `json:"raceName"`
Circuit Circuit `json:"Circuit"`
Date Date `json:"date"`
Time string `json:"time"`
URL string `json:"url"`
}
// Races is the list of races.
type Races struct {
Races []Race `json:"Races"`
Season string `json:"season"`
}
// RaceTable is the list of races.
type RaceTable struct {
RaceTable Races `json:"RaceTable"`
}
// MRData is the general wrapper from Eargast API.
type MRData struct {
MRData RaceTable `json:"MRData"`
}
It is a bit long and the first time, it did took me ages to understand this system. Also, if there are (vim-go)[https://github.com/fatih/vim-go] users, you can add the tags by, after having written the name and type of your structure, running :GoAddTags
and magic!
So the whole system of getting data, slice of bytes or API data, into workable JSON structure in Go is to know exactly the input your are going to get. You can trick your system by passing interface{}
but it won't be data that you'd be able to work with unfortunately. It is also possible to unmarshall an entire structure in a string but you would end up with the same problem: parsing this. Those workarounds are ok at some point but they defer a bit the point of all this work.
I wanted to mention also the package jsonq
which is super helpful to call quickly sub-objects or smaller sub-structure in larger JSON payload.
Thank you for reading and let me know if you have any questions!
Top comments (0)