Parse JSON API response in Go
Introduction
When you are hosting your model result as a micro-services, or scrapping data from websites, you will often find yourself working on some Restful API JSON object. In this post, I will show you how easily we can work with JSON data in Go.
Overview
- Get JSON response from sample API hosting site - reqres
- Generate go struct from the response - json-to-go
- Unmarshal JSON response to go struct
- Loop through the struct and print data from the result
Get Requests
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("https://reqres.in/api/users?page=2")
if err != nil {
fmt.Println("No response from request")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) // response body is []byte
fmt.Println(string(body)) // convert to string before print
}
Result JSON
{"page":2,"per_page":6,"total":12,"total_pages":2,"data":[{"id":7,"email":"michael.lawson@reqres.in","first_name":"Michael","last_name":"Lawson","avatar":"https://reqres.in/img/faces/7-image.jpg"},{"id":8,"email":"lindsay.ferguson@reqres.in","first_name":"Lindsay","last_name":"Ferguson","avatar":"https://reqres.in/img/faces/8-image.jpg"},{"id":9,"email":"tobias.funke@reqres.in","first_name":"Tobias","last_name":"Funke","avatar":"https://reqres.in/img/faces/9-image.jpg"},{"id":10,"email":"byron.fields@reqres.in","first_name":"Byron","last_name":"Fields","avatar":"https://reqres.in/img/faces/10-image.jpg"},{"id":11,"email":"george.edwards@reqres.in","first_name":"George","last_name":"Edwards","avatar":"https://reqres.in/img/faces/11-image.jpg"},{"id":12,"email":"rachel.howell@reqres.in","first_name":"Rachel","last_name":"Howell","avatar":"https://reqres.in/img/faces/12-image.jpg"}],"support":{"url":"https://reqres.in/#support-heading","text":"To keep ReqRes free, contributions towards server costs are appreciated!"}}
Convert JSON response
You can go to this site - JSON to go to convert JSON response to Go struct very easily.
Unmarshal JSON to Go struct
You can then unmarshal the `[]byte` from the GET response to the `Response` struct that we just auto-generated
// Generated go struct
type Response struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
TotalPages int `json:"total_pages"`
Data []struct {
ID int `json:"id"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Avatar string `json:"avatar"`
} `json:"data"`
Support struct {
URL string `json:"url"`
Text string `json:"text"`
} `json:"support"`
}
// snippet only
var result Response
if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
fmt.Println("Can not unmarshal JSON")
}
fmt.Println(PrettyPrint(result))
Response struct preview (partial)
{
"page": 2,
"per_page": 6,
"total": 12,
"total_pages": 2,
"data": [
{
"id": 7,
"email": "michael.lawson@reqres.in",
"first_name": "Michael",
"last_name": "Lawson",
"avatar": "https://reqres.in/img/faces/7-image.jpg"
},
{
"id": 8,
"email": "lindsay.ferguson@reqres.in",
"first_name": "Lindsay",
"last_name": "Ferguson",
"avatar": "https://reqres.in/img/faces/8-image.jpg"
}
]
}
Finally loop through the data node and print out the FirstName of the result
// Loop through the data node for the FirstName
for _, rec := range result.Data {
fmt.Println(rec.FirstName)
}
Complete code
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Response struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
TotalPages int `json:"total_pages"`
Data []struct {
ID int `json:"id"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Avatar string `json:"avatar"`
} `json:"data"`
Support struct {
URL string `json:"url"`
Text string `json:"text"`
} `json:"support"`
}
func main() {
// Get request
resp, err := http.Get("https://reqres.in/api/users?page=2")
if err != nil {
fmt.Println("No response from request")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) // response body is []byte
var result Response
if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to the go struct pointer
fmt.Println("Can not unmarshal JSON")
}
// fmt.Println(PrettyPrint(result))
// Loop through the data node for the FirstName
for _, rec := range result.Data {
fmt.Println(rec.FirstName)
}
}
// PrettyPrint to print struct in a readable way
func PrettyPrint(i interface{}) string {
s, _ := json.MarshalIndent(i, "", "\t")
return string(s)
}
You can find the complete working example in - Here
Demo
You can also find my article here on dev.to.
Recommended Readings
A nice way to set options in Go.
Easy static site crawling with golang goq package.
Reference Photo by Goran Ivos on Unsplash