Serializing/Deserializing a complex GO struct to store externally (i.e. in a database, redis, or text file)
- Posted by Michael MacDonald
- on May, 19, 2018
- in Go
- Blog No Comments.
Sometimes one needs to serialize data to store outside of a go application. One common approach is to save it as a JSON blob which can have it’s own challenges when retrieving it. In this article I will show you how to make use of GOB to serialize a complex struct into textual data than can be stored in any data store and then returned to its original structure when decoded.
package main
import (
"bytes"
"context"
"encoding/base64"
"encoding/gob"
"log"
"googlemaps.github.io/maps"
"github.com/davecgh/go-spew/spew"
)
func main() {
sourceStruct := getMap()
spew.Dump(sourceStruct) // Show the original structure to be encoded
valueToEncode := encodeToGob(&sourceStruct)
encodedBase64Value := base64encode(valueToEncode)
spew.Dump(encodedBase64Value) // Show the encoded value
/* Now that everything has been encoded we can decode it and we should get back the sane struct that we encoded */
/* We need to make the gob package aware of what types we've encoded so that we can decode it. */
gob.Register([]maps.GeocodingResult{})
var decodedStruct []maps.GeocodingResult
decodedValue := base64decode(encodedBase64Value)
decodeFromGob(decodedValue, &decodedStruct)
spew.Dump(decodedStruct) // Show the decoded structure, which should be the same as the original
/* Success */
}
func getMap() []maps.GeocodingResult {
APIKey := "[Google API KEY]"
c, _ := maps.NewClient(
maps.WithAPIKey(APIKey),
)
r := &maps.GeocodingRequest{
Address: "1600 Pennsylvania Ave NW",
Region: "us",
}
response, err := c.Geocode(context.Background(), r)
if err != nil {
log.Fatal(err)
}
return response
}
func encodeToGob(source interface{}) []byte {
var buff bytes.Buffer
encoder := gob.NewEncoder(&buff)
err := encoder.Encode(source)
if err != nil {
log.Fatal(err)
}
return buff.Bytes()
}
func decodeFromGob(source []byte, destination interface{}) {
decoder := gob.NewDecoder(bytes.NewBuffer(source))
err := decoder.Decode(destination)
if err != nil {
log.Fatal(err)
}
}
func base64encode(source []byte) []byte {
encodedBytes := make([]byte, base64.URLEncoding.EncodedLen(len(source)))
base64.URLEncoding.Encode(encodedBytes, source)
return encodedBytes
}
func base64decode(source []byte) []byte {
decodedBytes := make([]byte, base64.URLEncoding.DecodedLen(len(source)))
_, err := base64.URLEncoding.Decode(decodedBytes, source)
if err != nil {
log.Fatal(err)
}
return decodedBytes
}
Related
Comments & Responses
Recent Posts
- The shape of structured data
- Writing very small executable
- The challenge of type asserting []interface{} to string slices.
- Serializing/Deserializing a complex GO struct to store externally (i.e. in a database, redis, or text file)
- Fun with golang, Google Maps api, and proxying requests
