mbfrahry
mbfrahry

Reputation: 603

JSON golang boolean omitempty

I'm having issues with writing a golang library for an api. The json aspect of booleans is causing issues.

Let's say the default value of a boolean is true for an api call.

If I do

SomeValue bool `json:some_value,omitempty`

and I don't set the value through the library, the value will be set to true. If I set the value to false in the library, omitempty says that a false value is an empty value so the value will stay true through the api call.

Let's take out the omitempty and have it look like this

SomeValue bool `json:some_value`

Now I have the opposite issue, I can set the value to false but if I don't set the value then the value will be false even though I expect it to be true.

Edit: How do I maintain the behavior of not having to set the value to true while also being able to set the value to false?

Upvotes: 60

Views: 42538

Answers (2)

omarwaleed
omarwaleed

Reputation: 681

As a continuation to gaav's answer. I had the same problem with unmarshalling instead. If you want to check that the value is provided or not, simply check if the pointer is nil or not

type SomeStruct struct {
    SomeValue *bool `json:"some_value,omitempty"`
}

func HandleApiRequest(w http.ResponseWriter, r *http.Request) {
  body := new(SomeStruct)

  reqBody, err := ioutil.ReadAll(r.Body)
  if err != nil {
         panic(err)
  }

  err := json.Unmarshal(reqBody, body)
  if err != nil {
    panic(err)
  }

  if body.SomeValue != nil {
    // SomeValue is provided in the body and is a valid boolean
    // Do something with *body.SomeValue
    log.Println("Some Value is:", *body.SomeValue)
  } else {
    // SomeValue was NOT sent in json body
    // Will panic with a fault if you tried accessing *body.SomeValue
  }
}

Upvotes: 1

gavv
gavv

Reputation: 4893

Use pointers

package main

import (
    "encoding/json"
    "fmt"
)

type SomeStruct struct {
    SomeValue *bool `json:"some_value,omitempty"`
}

func main() {
    t := new(bool)
    f := new(bool)

    *t = true
    *f = false

    s1, _ := json.Marshal(SomeStruct{nil})
    s2, _ := json.Marshal(SomeStruct{t})
    s3, _ := json.Marshal(SomeStruct{f})

    fmt.Println(string(s1))
    fmt.Println(string(s2))
    fmt.Println(string(s3))
}

Output:

{}
{"some_value":true}
{"some_value":false}

Upvotes: 91

Related Questions