Render table in html template where table-data are keys and values of some json data in Golang

408 Views Asked by At

In backend I send http request to some third party site and retrieve some json data in response. Keys in the json response are not always same, but I have some idea of what they might be. For example:

Sending request to example.com/data/1 could bring the following:

{
  "File.Trimmed": 54,
  "Feature": "Generic"
}

While requesting to example.com/data/2 could bring the following:

{
  "File.Trimmed": 83,
  "Object.Notation": "Reverse"
}

My objective is to render html tables in the frontend using the key-value pairs in exact same order as they were in the response.

So the first table would be:

Column A Column B
File.Trimmed 54
Feature Generic

And the second table:

Column A Column B
File.Trimmed 83
Object.Notation Reverse

I have made the following struct to deal with this data:

type FileDetails struct {
    FileTrimmed int `json:"File.Trimmed,omitempty"`
    Feature string `json:"Feature,omitempty"`
    ObjectNotation string `json:"Object.Notation,omitempty"`
}

// cannot use map[string]interface{} because that would destroy the order
var data FileDetails
err = json.NewDecoder(res.Body).Decode(&data)

At this point I am struggling how to send data to the template and render the tables. It's possible to get the json tags (content for Column A) from the struct instance using reflect, but is it possible to get field names like that in {{range}} loops in the template? If possible, then how?

Or is there any better way to achieve my main objective?

1

There are 1 best solutions below

0
On

Keys in the json response are not always same

If the keys are not always the same, it's better to use map instead of struct. But as like you said that would destroy the order.

One approach we could try when you have some idea of what they might be

  • we should parse the response into a map[string]interface{}
  • and then we will create string slice which will have the key names as ordered. (You already know what will be the response keys)

And here is the sample

var result map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
    panic(err)
}

tableTemplate := `
        <table>
        <tr>
            <th>Column A</th>
            <th>Column B</th>
        </tr>
        {{range .Keys}}
            <tr>
                <td>{{.}}</td>
                <td>{{index $.Data .}}</td>
            </tr>
        {{end}}
        </table>

`

tmpl := template.New("table")
tmpl, err = tmpl.Parse(tableTemplate)
if err != nil {
    fmt.Println("Error parsing template:", err)
    return
}

templateData := map[string]interface{}{
    "Data": result,
    "Keys": []string{
        "File.Trimmed", "Feature", "Object.Notation",
    },
}

err = tmpl.Execute(w, templateData)
if err != nil {
    fmt.Println("Error executing template:", err)
    return
}

This will keep the content printed as an ordered manner.