jsongounmarshalling

JSON data Unmarshal with diffrent field names in array


Im trying to Unmarshal some JSON data. I think the problem is that the 2 arrays have different fields so do not properly match my struct. Essentially I only need the data from the first item in the array. Is there a way to deal with this. Here's what I have, however it's not throwing any errors but it doesn't seem to be returning anything.

Here's an example in go playground

package main

import (
    "encoding/json"
    "fmt"
    "time"
)

var jsondata = `{
  "Secrets": [
    {
      "name": "default",
      "versionInfo": "2025-02-10T20:11:05Z/1",
      "lastUpdated": "2025-02-10T20:11:05.512Z",
      "secret": {
        "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
        "name": "default",
        "tlsCertificate": {
          "certificateChain": {
            "inlineBytes": "RRVkp2YjNSRApRVEV1WTN=="
          },
          "privateKey": {
            "inlineBytes": "W3JlZFRDSGVkXQ=="
          }
        }
      }
    },
    {
      "name": "default2",
      "versionInfo": "2025-02-10T20:11:05Z/3",
      "lastUpdated": "2025-02-10T20:11:05.527Z",
      "secret": {
        "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret",
        "name": "ROOTCA",
        "validationContext": {
          "trustedCa": {
            "inlineBytes": "LS0tLS1CRUdJTiBDRVJUSUZJ="
          }
        }
      }
    }
  ]
}`

type model struct {
    Name        string    `json:"name"`
    VersionInfo time.Time `json:"versionInfo"`
    LastUpdated time.Time `json:"lastUpdated"`
    Secret      struct {
        Type           string `json:"@type"`
        Name           string `json:"name"`
        TLSCertificate struct {
            CertificateChain struct {
                InlineBytes string `json:"inlineBytes"`
            } `json:"certificateChain"`
            PrivateKey struct {
                InlineBytes string `json:"inlineBytes"`
            } `json:"privateKey"`
        } `json:"tlsCertificate"`
    } `json:"secret"`
}

func main() {

    input := []byte(jsondata)
    //Source := (*json.RawMessage)(&data2)

    var Info model
    // Notice the dereferencing asterisk *
    err := json.Unmarshal(input, &Info)
    if err != nil {
        //fmt.Printf(err.Error())
        panic(err)
    }
    fmt.Printf("%s", Info.Name)

}

Solution

  • Your input JSON is an object that has a Secrets property which is a JSON array. You have to model this with a slice in Go, like this:

    type wrapper struct {
        Secrets []*model `json:"Secrets"`
    }
    

    And inside JSON the versionInfo is not a valid time (notice the trailing /1 and /3, use string and you can process it later:

    VersionInfo string    `json:"versionInfo"`
    

    Now parsing your input:

    input := []byte(jsondata)
    
    var w wrapper
    err := json.Unmarshal(input, &w)
    
    if err != nil {
        panic(err)
    }
    
    for _, model := range w.Secrets {
        fmt.Printf("Name: %s, secret name: %s\n", model.Name, model.Secret.Name)
    }
    

    This will output (try it on the Go Playground):

    Name: default, secret name: default
    Name: default2, secret name: ROOTCA