Nancyme
Nancyme

Reputation: 43

Error Parsing Json using Go language

I am trying to Parse Json & Print Data and save in a CSV using GO language .

It is printing the desired 10 result per page with Println but couldn't parse JSON .

This is what I am doing

  1. Visitor visits studentresults.com/page=1 RollNo. & Marks for 10 students are displayed and it is also saved in a CSV [key.rollno & key.marks]

  2. Program Makes a request to studentsapimarks.com/api/rollno1,rollno2,rollno3/detail (appending all key.rollno that we got in step1) The Json response would be like

    [{"name":"James","Percentage":96.5,"Remarks":"VeryGood"}, 
    {"name":"William","Percentage":36.0,"Remarks":"Bad"}, 
    {"name":"Jacob","Percentage":63.0,"Remarks":"Average"}, 
    {"name":"Wilson","Percentage":69.3,"Remarks":"Average"}, 
    {"name":"Kurtson","Percentage":16.9,"Remarks":"VeryBad"}, 
    {"name":"Tom","Percentage":86.3,"Remarks":"Good"}]
    
  3. Extract Name & Percentage fields & save in a csv

Here is my snippet of the code that is responsible for printing and saving the results

package main

import (
    "encoding/csv"
    "fmt"
    "net/http"
    "os"
    "strings"
    "encoding/json"

)


type Key struct {
    fname      string
    marks      int
    rollno     int
    }

type object struct {
    Percentage float64
    Name string `json:"name"`
    }


func PageRequest(w http.ResponseWriter, r *http.Request) {


    // Page header
    fmt.Fprintf(w, PageHeader, pages, previous, next)

    // Save in csv
    csvfile, err := os.OpenFile("marks.csv", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer csvfile.Close()

    writer := csv.NewWriter(csvfile)
    defer writer.Flush()

    // Defining RollNos
    var rollNos []string

    // Marks for UID
    UID, length := compute(start)
    for i := 0; i < length; i++ {
        key := UID[i]

    // Prints firstname, Marks and Rollno
        fmt.Fprintf(w, key.fname, key.marks, key.rollno) 



        records := [][]string{{key.fname, key.marks, key.rollno}}

        for _, record := range records {
            err := writer.Write(record)
            if err != nil {
                fmt.Println("Error:", err)
                return
            }
        }

    // Append All key.rollno
        rollNos := append(rollNos, key.rollno)

    // Makes a request to as studentsapimarks.com/api/rollno1,rollno2,rollno3/detail
        uri := "https://studentsapimarks.com/api/" + strings.Join(rollNos, ",") + "/detail"

        res, err := http.Get(uri)
        if err != nil {
            log.Fatal(err)
        }
        defer res.Body.Close()

        var s []object
        err = json.NewDecoder(res.Body).Decode(&s)
        if err != nil {
            log.Fatal(err)
        }

    // Prints Name/ Percentage
        fmt.Println(s[0].Name)
        fmt.Println(s[0].Percentage)
    }

    // Page Footer
    fmt.Fprintf(w, PageFooter, previous, next)
}


func main() {
    http.HandleFunc("/", PageRequest)

log.Println("Listening")
log.Fatal(http.ListenAndServe(":8080", nil))

}

fmt.Fprintf(w, key.fname, key.marks, key.rollno) is working fine and displays all 10 results per page and saves in a csv .

Problem with the code is

  1. It is not appending all key.rollno that we got in step1 as studentsapimarks.com/api/rollno1,rollno2,rollno3/detail

  2. Also how could i save the JSON extracted s[0].name results in a CSV ?

Upvotes: 2

Views: 1457

Answers (1)

Adrian
Adrian

Reputation: 46602

The JSON parsing is failing because you're trying to unmarshal a JSON array into a struct. You want to unmarshal a JSON array into a slice - the outer struct is not necessary:

var s []object
err = json.NewDecoder(res.Body).Decode(&s)

Also, it can only unmarshal exported fields (those that start with a capital letter), so to get the name, you'll need to change your struct definition. I'm guessing the percentage isn't coming through either, since in the JSON it's a single float value, but in your struct you're taking a float slice.

type object struct {
    // "Percentage": 96.4 is not a slice.
    // Also if the field name in Go and JSON are identical, you dont need the json tag.
    Percentage float64
    // The field must be capitalized, the tag can stay lowercase
    Name string `json:"name"`
}

Then you'll access those fields accordingly:

// Prints Name/ Percentage
fmt.Println(s[0].Name)
fmt.Println(s[0].Percentage)

Upvotes: 1

Related Questions