Search code examples
jsongomarshallinggo-gin

How to remove certain items from a struct received from an imported package in golang?


I am receiving an item from a package of an imported third-party module:

myItem := importedPackage.get()

It is a struct like this:

type ImportedStruct struct {
    Ip                  net.IP                  `json:"ip"`
    Index               uint32                  `json:"index"`
    LocalIndex          uint32                  `json:"localIndex"`
    RemoteIndex         []*udp.Addr             `json:"remoteIndex"`
    Certificates        *certificates           `json:"certificates"`
    VpnAddress          []iputil.VpnIp          `json:"vpnAddress"`
}

I would like to remove one or more of the items there, before returning it from my Golang Gin API as JSON:

c.JSON(200, &myItem)

The issue is trying to find the most resource efficient way to do this.

I have considered a loop and writing the fields I need to a new struct:

newItem := make([]ImportedStruct, len(myItem))

i := 0
for _, v := range myItem {
    newItem[i] = ...
    ...
}

c.JSON(200, &hostList)

I also considered marshalling and then unmarshalling to assign it to another struct before returning it through the API:

// Marshal the host map to json
marshaledJson, err := json.Marshal(newItem)
if err != nil {
    log.Error(err)
    c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    return
}

// Unmarshal the json into structs
var unmarshalledJson []ImportedStruct
err = json.Unmarshal(marshaledJson, &unmarshalledJson)
if err != nil {
    log.Error(err)
    c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    return
}

// Return the modified host map
c.JSON(200, &unmarshalledJson)

I'm hoping though to find a more efficient way to do this. myItem could contain over 3m lines of JSON, and looping through it all, or marshalling and unmarshalling seems like it involves more processes then it needs just to achieve something relatively simple.

Edit: The struct is a slice ([]).


Solution

  • Define a new struct that is a copy of the one you have, with different tags:

    type ImportedStructMarshal struct {
        Ip                  net.IP                  `json:"ip"`
        Index               uint32                  `json:"index"`
        LocalIndex          uint32                  `json:"-"`
        RemoteIndex         []*udp.Addr             `json:"remoteIndex"`
        Certificates        *certificates           `json:"certificates"`
        VpnAddress          []iputil.VpnIp          `json:"vpnAddress"`
    }
    

    Then, use this new struct to marshal:

    var input ImportedStruct
    forMarshal:=ImportedStructMarshal(input)
    ...
    

    This will work as long as the new struct is field-by-field compatible with the imported struct.