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

  1. Get JSON response from sample API hosting site - reqres
  2. Generate go struct from the response - json-to-go
  3. Unmarshal JSON response to go struct
  4. 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":"[email protected]","first_name":"Michael","last_name":"Lawson","avatar":"https://reqres.in/img/faces/7-image.jpg"},{"id":8,"email":"[email protected]","first_name":"Lindsay","last_name":"Ferguson","avatar":"https://reqres.in/img/faces/8-image.jpg"},{"id":9,"email":"[email protected]","first_name":"Tobias","last_name":"Funke","avatar":"https://reqres.in/img/faces/9-image.jpg"},{"id":10,"email":"[email protected]","first_name":"Byron","last_name":"Fields","avatar":"https://reqres.in/img/faces/10-image.jpg"},{"id":11,"email":"[email protected]","first_name":"George","last_name":"Edwards","avatar":"https://reqres.in/img/faces/11-image.jpg"},{"id":12,"email":"[email protected]","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": "[email protected]",
        "first_name": "Michael",
        "last_name": "Lawson",
        "avatar": "https://reqres.in/img/faces/7-image.jpg"
    },
        {
        "id": 8,
        "email": "[email protected]",
        "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)
}

Demo

You can find the original post on my site - Here

17