If an object defines an optional boolean property it does not end up in the JSON if the value is false
2.2.2
swagger: '2.0'
info:
description: 'Demonstrate golang codegen bug'
version: 1.0.0
schemes:
- http
paths:
/pet:
post:
summary: Add a new pet to the store
description: ''
operationId: addPet
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: body
description: Pet object that needs to be added to the store
required: true
schema:
$ref: '#/definitions/Pet'
responses:
'405':
description: Invalid input
definitions:
Pet:
title: a Pet
description: A pet for sale in the pet store
type: object
required:
- name
properties:
id:
type: integer
format: int64
name:
type: string
example: doggie
vaccinated:
type: boolean
description: Indicates whether the Pet's vaccinations are up-to-date
java -jar target/swagger-codegen-cli.jar generate -i ./mypetstore.yaml -l go -o ./mypetstore-client-go
Include an optional boolean property (like vaccinated in the API above), set to false and encode it. The field will be missing from the JSON.
If the property is marked as required then things work as expected which I guess was a result of https://github.com/swagger-api/swagger-codegen/issues/4665
Don't use omitempty for boolean properties, even if optional...
from https://golang.org/pkg/encoding/json/
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
..if you do then sending a false for optional properties is not possible.
@drennalls Can you please try the latest stable version (2.3.0), which has the Go API client refactored?
This happens in version 2.4.0-SNAPSHOT. Reproduced as follows:
Got petstore.yaml
And add:
...
vaccinated:
type: boolean
description: indicate if pet is vaccinated
...
To the Pet object definition.
Generate the client:
$ ./run-in-docker.sh generate -i issue7391.yaml -l go -o /gen/out/issue7391 -DpackageName=issue7391
$ ln -s ${PWD}/out $(go env GOPATH)/src/out
Create a dummy server:
from flask import Flask, request
app = Flask(__name__)
@app.route('/pet', methods=['POST'])
def root():
content = request.json
print content
return "all right"
app.run(port=8080)
Run a Go test:
package main
import (
"fmt"
"out/issue7391"
"testing"
)
func TestPost(t *testing.T) {
config := issue7391.NewConfiguration()
config.BasePath = "http://localhost:8080"
client := issue7391.NewAPIClient(config)
pet := issue7391.Pet{
Name: "john",
// Vaccinated: false,
}
res, err := client.PetApi.AddPet(nil, pet)
fmt.Printf("%+v\n%+v\n", res, err)
}
Running with or without commenting on that line, the server logs:
{u'name': u'john', u'photoUrls': None}
127.0.0.1 - - [31/Jan/2018 11:59:48] "POST /pet HTTP/1.1" 200 -
Manually changing the model_pet.go generated from:
...
Vaccinated bool `json:"vaccinated,omitempty"`
...
to
...
Vaccinated bool `json:"vaccinated"`
...
Again, running with or without commenting the Vaccinated: false line, the server logs:
127.0.0.1 - - [31/Jan/2018 11:59:58] "POST /pet HTTP/1.1" 200 -
{u'vaccinated': False, u'name': u'john', u'photoUrls': None}
So removing omitempty won't fix the problem, since the property will always be false if empty. Surprisingly, changing the property to:
...
Vaccinated *bool `json:"vaccinated"`
...
Actualy works as intended. Maybe it's an option?
/cc @drennalls @wing328
I thought removing omitempty would work. Can you also share the Go version you're using?
cc @antihax @bvwells
Sure:
$ go version
go version go1.9.3 linux/amd64
@drennalls hello, setting default value should help
vaccinated:
type: boolean
default:false
description: indicate if pet is vaccinated
I seem to be running into this issue as well. Providing a default as @tenmozes suggested yields
Vaccinated *bool `json:"vaccinated,omitempty"`
which does work. However, my question is whether we should also consider using this style even when a default is NOT provided?
Personally, I can't think of an instance where the existing
Vaccinated bool `json:"vaccinated,omitempty"`
would be preferred over the pointer version that is generated when you provide a default. What do y'all think / can you think of one such scenario? In fact, wouldn't we run into this same issue with all scalar types (e.g., int, string)? Under the current scheme there is no way to pass 0 or an empty string unless you specify a default.
It seems the fix by setting a default outlined in https://github.com/swagger-api/swagger-codegen/issues/7391#issuecomment-373355961 does not work for fields of type number when the default is 0.
The following:
latitude:
type: number
description: the latitude in decimal format
leads to
Latitude float32 `json:"latitude,omitempty"`
as expected.
Setting a default other than 0 will lead to the expecting pointer construct, such as:
latitude:
type: number
default: 5
description: the latitude in decimal format
leads to
Latitude *float32 `json:"latitude,omitempty"`
as expected after knowing this fixes it for bool fields as well.
However, when the default is 0 (which is the default value of a float32, similar to how false is the default value of a bool), we don't end up with the pointer construct:
latitude:
type: number
default: 0
description: the latitude in decimal format
leads to
Latitude float32 `json:"latitude,omitempty"`
So, fixing this by setting a default, does not work if the default is 0.
I'm testing with version CLI 2.4.8 and it's no longer generating pointers for booleans when setting a default value.
I am also seeing the bool issue - on Golang 1.12.6 and go-swagger latest (c49ea4ca2).
The fix does seem to be making the struct member a pointer in the model - which as suggested, a default value does - and also making the property required, eg :
GroupQueryResult:
description: Result of a group query
type: object
required:
- group
- user
- isMember
properties:
user:
type: string
group:
type: string
isMember:
type: boolean
any updates?
Most helpful comment
any updates?