Go adding a extra line in API response when reading from a csv file

Issue

When uploading a file through my frontend (React), Go is reading the csv file and then sending the data in a structured format in a JSON response.

The JSON response:

{
    "Success": true,
    "labels": [
        "Jan",
        "Feb",
        "Mar",
        "Apr",
        "May",
        "Jun",
        "Jul",
        "Aug",
        "Sep",
        "Oct",
        "Nov",
        "Dec"
    ],
    "data": [
        {
            "label": "",
            "data": null,
            "borderColor": "",
            "backgroundColor": ""
        },
        {
            "label": "Kyle",
            "data": [
                "1517",
                "1689",
                "1719",
                "1591",
                "1490",
                "1310",
                "1533",
                "1500",
                "1400",
                "1300",
                "1600",
                "1800"
            ],
            "borderColor": "#f6ff00",
            "backgroundColor": "#f6ff00"
        },
        {
            "label": "Mickey",
            "data": [
                "3000",
                "3100",
                "3200",
                "3000",
                "3500",
                "4000",
                "3700",
                "3500",
                "3000",
                "4000",
                "5000",
                "4000"
            ],
            "borderColor": "#ff0000",
            "backgroundColor": "#ff0000"
        },
        {
            "label": "Donald",
            "data": [
                "2500",
                "2000",
                "2800",
                "3000",
                "3100",
                "2900",
                "2800",
                "3000",
                "3200",
                "3400",
                "3500",
                "3800"
            ],
            "borderColor": "#001eff",
            "backgroundColor": "#001eff"
        }
    ]
}

You see the problem is this line under data:

{"label":"","data":null,"borderColor":"","backgroundColor":""}

I do not know why this is being added in by Go

The CSV file:

,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Kyle,1517,1689,1719,1591,1490,1310,1533,1500,1400,1300,1600,1800
Mickey,3000,3100,3200,3000,3500,4000,3700,3500,3000,4000,5000,4000
Donald,2500,2000,2800,3000,3100,2900,2800,3000,3200,3400,3500,3800
func RouteUpload(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

    r.ParseMultipartForm(16 * 1024 * 1024) // 16MB
    file, handler, err := r.FormFile("file")
    if err != nil {
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    defer file.Close()

    // Create an empty file on filesystem
    f, err := os.OpenFile(filepath.Join("uploads", handler.Filename), os.O_WRONLY|os.O_CREATE, 0666)
    defer f.Close()

    // Copy the file to the images directory
    io.Copy(f, file)
    w.Header().Set("Content-Type", "application/json")

    type MyData struct {
        Label           string   `json:"label"`
        Data            []string `json:"data"`
        BorderColor     string   `json:"borderColor"`
        BackgroundColor string   `json:"backgroundColor"`
    }

    type MyFile struct {
        Success bool     `json:"Success"`
        Labels  []string `json:"labels"`
        Data    []MyData `json:"data"`
    }

    var myData MyData
    var myFile MyFile

    path := "uploads/" + handler.Filename

    // open file
    fi, err := os.Open(path)
    if err != nil {
        log.Fatal(err)
    }

    // remember to close the file at the end of the program
    defer f.Close()

    // read csv values using csv.Reader
    csvReader := csv.NewReader(fi)
    data, err := csvReader.ReadAll()
    if err != nil {
        fmt.Println(err)
    }

    colors := []string{"#00ff12", "#f6ff00", "#ff0000", "#001eff", "#ea00ff", "#ff9600"}

    for i, line := range data {
        if i == 0 {
            for j, field := range line {
                if j == 0 {

                } else {
                    myFile.Labels = append(myFile.Labels, field)
                }
            }
        } else {
            fmt.Println(line)
            for j, field := range line {
                if j == 0 {
                    myData.Label = field
                } else {
                    myData.Data = append(myData.Data, field)
                }
            }
            myData.BorderColor = colors[i]
            myData.BackgroundColor = colors[i]
        }
        myFile.Data = append(myFile.Data, myData)
        myData.Data = []string{}
    }

    myFile.Success = true

    // Marshal into JSON
    responseJson, err := json.Marshal(myFile)
    if err != nil {
        fmt.Println(err)
    }

    // Send success response to user in JSON
    fmt.Fprintf(w, "%s\n", responseJson)
}

Solution

You are treating the first line from the CSV file differently than the others because of the if i==0 {...} else {...}, but after that you are always appending to myFile.Data – so for i==0, the empty myData will be appended. Try moving this append into the else block.

Some other suggestions: if ... else is actually discouraged in Go (see https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea88). So for the if i==0, you could avoid the else by using continue after the for loop – then you could move the code out of the else block. Also, the if j==0 {/*do nothing*/} else {/*do something*/} should of course be if j!=0 {/*do something*/}.

Answered By – rob74

Answer Checked By – Mildred Charles (GoLangFix Admin)

Leave a Reply

Your email address will not be published.