Home > Software engineering >  How to store data from a HTTP Get request in a slice of structs
How to store data from a HTTP Get request in a slice of structs

Time:08-08

Problem I'm new to Go and I'm trying to store json data in a struct from the Gov.uk public holidays API, so I can use this later on in my frontend.

If I run

var sb = string(body)
fmt.Println(sb)

I can see the data that's being returned in my terminal. I know that the response body is made up of bytes and the above converts it to a string.

I would like to iterate through the response body and store the data in a slice of structs called holidays, each struct will contain the data for a single public holiday. For some reason, the holidays variable returns an empty slice: [].

I guess my two questions are:

  1. What's the best way to transform json data into a slice of structs to be used later on?
  2. Why does the holidays variable return an empty slice?

Thanks!

Here's my code below: package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

type Response struct {
    Data []Data
}

type Data struct {
    Division    string
    Bankholiday Bankholiday
}

type Bankholiday struct {
    Title string
    Date  string
}

func main() {
    resp, err := http.Get("https://www.gov.uk/bank-holidays.json")
    if err != nil {
        log.Fatal(err)
    }

    if resp.Body != nil {
        defer resp.Body.Close()
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }

    var response Response
    json.Unmarshal(body, &response)
    var holidays = []Bankholiday{}

    for _, date := range response.Data {
        holidays = append(holidays, Bankholiday{
            Title: date.Bankholiday.Title,
            Date:  date.Bankholiday.Date,
        })
    }

    fmt.Println("holidays: ", holidays)

}

CodePudding user response:

I had to adjust the Response struct to handle correct unmarshaling of data. Find below the working code:

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type Response map[string]Data

type Data struct {
    Division string `json:"division"`
    Events   []struct {
        Title   string `json:"title"`
        Date    string `json:"date"`
        Notes   string `json:"notes"`
        Bunting bool   `json:"bunting"`
    } `json:"events"`
}

func main() {
    resp, err := http.Get("https://www.gov.uk/bank-holidays.json")
    if err != nil {
        log.Fatal(err)
    }

    if resp.Body != nil {
        defer resp.Body.Close()
    }

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }

    var response Response
    if err = json.Unmarshal(body, &response); err != nil {
        log.Fatalln(err)
    }

    for div, _ := range response {
        for _, event := range response[div].Events {
            fmt.Printf("Division=%s, Holiday=%s, Date=%s\n", div, event.Title, event.Date)
        }

    }

}

CodePudding user response:

Because your json fields must match your structs.

type Response map[string]Data

type Data struct {
    Division string  `json:"division"`
    Events   []Event `json:"events"`
}

type Event struct {
    Title   string `json:"title"`
    Date    string `json:"date"`
    Notes   string `json:"notes"`
    Bunting bool   `json:"bunting"`
}
  • Related