0

I am implementing a String() method on a type I have. This type's fields provide optional configuration options, and a user may choose to add any combination of those fields without necessarily needing all of them. The end result needs to be formatted as a JSON string (dictated by external service I'm consuming, not my choice).

Edit: a bit of additional context. The reason I need a String() method is because when I actually provide a value of this type to the external service, it will be formatted as a URL encoded string.

My approach was something along the lines of:


type AnotherStruct struct {
    FieldA []string
    FieldB []string
}

type Spec struct {
    FieldA []string
    FieldB int
    FieldC AnotherStruct
}

func (s Spec) String() string {
    args := make([]any, 0)
    f := "{"
    if s.FieldA != nil {
        f += `"fieldA": %v, `
        args = append(args, s.FieldA)
    }
    if s.FieldB != 0 {
        f += `"fieldB": %d, `
        args = append(args, s.FieldB)
    }
    if !reflect.DeepEqual(s.FieldC, AnotherStruct{}) {
        f += `"fieldC": %v, `
        args = append(args, s.FieldC)
    }
    f += "}"

    return fmt.Sprintf(f, args...)
}

But this seems clunky. Is there a clean way to implement such a method in Go?

0

1 Answer 1

0

There's no reason to create a String method in your case. Everything* you're aiming to do is already handled by the standard library encoding/json package.

The idiomatic way to do what you're after is with JSON struct tags:

type Spec struct {
    FieldA []string       `json:"fieldA,omitempty"`
    FieldB int            `json:"fieldB,omitempty"`
    FieldC *AnotherStruct `json:"fieldC,omitempty"`
}

Then just call json.Marshal() on your value:

s := Spec{
    FieldA: []string{"one", "two"},
    // FieldB & FieldC omitted
}
output, err := json.Marshal(s)
if err != nil {
    panic(err)
}
fmt.Println(string(output))

Prints:

{"fieldA":["one","two"]}

*The only change I had to make to conform to the standard library expectations was to make FieldC a pointer to AnotherStruct:

    FieldC *AnotherStruct `json:"fieldC,omitempty"`

instead of

    FieldC AnotherStruct `json:"fieldC,omitempty"`
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.