DEV Community

Eray Ates
Eray Ates

Posted on

Read long-short syntax of config in Go

Lets think we have config file like: (I use json)

This is short syntax

{
    "network": "test-network"
}
Enter fullscreen mode Exit fullscreen mode

And long syntax

{
    "network": {
        "name": "test-network",
        "description": "for testing purposes"
    }
}
Enter fullscreen mode Exit fullscreen mode

When reading this configurations we should give own decoder function to parse and write to the our object.

Before to do that lets check our example.

First create struct for long and short format and try unmarshal.

package main

import (
    "encoding/json"
    "fmt"
)

type NetworkDescription struct {
    Name        string `json:"name"`
    Description string `json:"description"`
}

type NetworkLong struct {
    Network NetworkDescription `json:"network"`
}

type NetworkShort struct {
    Network string `json:"network"`
}

func main() {
    networkLongTest1 := &NetworkLong{}
    err := json.Unmarshal([]byte(`{"network":{"name":"foo","description":"bar"}}`), networkLongTest1)
    fmt.Printf("%#v\nErr: %v", networkLongTest1, err)

    networkLongTest2 := &NetworkLong{}
    err = json.Unmarshal([]byte(`{"network":"foo"}`), networkLongTest2)
    fmt.Printf("%#v\nErr: %v", networkLongTest2, err)
}
Enter fullscreen mode Exit fullscreen mode

Result obviously give error in second try

$ go run main.go
&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:"bar"}}
Err: <nil>
&main.NetworkLong{Network:main.NetworkDescription{Name:"", Description:""}}
Err: json: cannot unmarshal string into Go struct field NetworkLong.network of type main.NetworkDescription
Enter fullscreen mode Exit fullscreen mode

Good now we can use this error in our custom Unmarshaler's interface implementation.

I am using stdlib's json to unmarshaller so Unmarshaler interface has one function UnmarshalJSON([]byte) error

We can create new struct type and use that one but I will just modify our NetworkLong struct because I will turn short version to the long.

type NetworkLong struct {
    Network NetworkDescription `json:"network"`
}

func (n *NetworkLong) UnmarshalJSON(b []byte) error {
    // change type to don't use our custom unmarshal
    type longFormat NetworkLong
    nLong := &longFormat{}
    err := json.Unmarshal(b, &nLong)
    if err != nil {
        nShort := &NetworkShort{}
        err = json.Unmarshal(b, nShort)
        if err != nil {
            return err
        }

        n.Network = NetworkDescription{
            Name: nShort.Network,
        }

        return nil
    }

    *n = NetworkLong(*nLong)

    return nil
}
Enter fullscreen mode Exit fullscreen mode

And our result is

&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:"bar"}}
Err: <nil>
&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:""}}
Err: <nil>
Enter fullscreen mode Exit fullscreen mode

Check in the playground

Top comments (0)