go-restful-openapi icon indicating copy to clipboard operation
go-restful-openapi copied to clipboard

struct with json.Marshaler fail to build schema

Open slow-zhang opened this issue 4 years ago • 8 comments

the code of https://github.com/emicklei/go-restful-openapi/ is here: image

test struct

type Conn struct {
	URL string
}

func (v Conn) MarshalJSON() ([]byte, error) { ... }

type A struct {
	ID   int
	Conn Conn
}

open-api json struct

{
"ID": "stirng"
"Conn": "string"
}

slow-zhang avatar Nov 16 '21 10:11 slow-zhang

thank you reporting this. Could you help me by providing a testcase for this?

emicklei avatar Nov 21 '21 08:11 emicklei

is there some examples for adding a test cases

slow-zhang avatar Dec 16 '21 06:12 slow-zhang

here is the test

type Parent struct {
	FieldA string
}

func (v Parent) MarshalJSON() ([]byte, error) { return nil,nil }

type Child struct {
	FieldA Parent
	FieldB int
}

func TestParentChildArray(t *testing.T) {
	db := definitionBuilder{Definitions: spec.Definitions{}, Config: Config{}}
	db.addModelFrom(Child{})
	s := spec.Schema{
		SchemaProps: spec.SchemaProps{
			Definitions: db.Definitions,
		},
	}
	data, _ := json.MarshalIndent(s, "", "  ")
	log.Fatalln(string(data))
}

output:

{
  "definitions": {
    "restfulspec.Child": {
      "required": [
        "FieldA",
        "FieldB"
      ],
      "properties": {
        "FieldA": {
          "type": "string"
        },
        "FieldB": {
          "type": "integer",
          "format": "int32"
        }
      }
    }
  }
}

slow-zhang avatar Dec 16 '21 06:12 slow-zhang

thank you for the test, I will look for a solution

emicklei avatar Nov 30 '22 21:11 emicklei

@.***:377636000地址:浙江省杭州市西湖区浙江大学西溪校区

slow-zhang avatar Nov 30 '22 21:11 slow-zhang

@emicklei have you considered simply deleting the code block checking for the custom marhalling? What is it for anyway?

Found this because I was having a similar (the same?) problem. I have a type

// ValidJSONArray represents a generic slice which, when marshalled to json, will give an empty array
// for both nil and empty slices.  This prevents a field which a client expects to be an array from being "null"
type ValidJSONArray[T any] []T

func (v ValidJSONArray[T]) MarshalJSON() ([]byte, error) {
	if v == nil {
		v = make([]T, 0)
	}
	return json.Marshal([]T(v))
}

and when I replaced my slice properties with ValidJSONArray, suddently they all had type of "string" in the open api spec!

e.g. this produces a correct spec:

type ClaimByKeysReq struct {
	Keys []string `json:"keys"`
	Regions   []string `json:"regions"`
}

but this does not

type ClaimByKeysReq struct {
	Keys ValidJSONArray[string] `json:"keys"`
	Regions   ValidJSONArray[string] `json:"regions"`
}

however, if I just delete the code block in the screenshot in the original post on this issue, it works exactly as expected.

bjornbyte avatar Jun 27 '23 18:06 bjornbyte

@.***:377636000地址:浙江省杭州市西湖区浙江大学西溪校区

slow-zhang avatar Jun 27 '23 18:06 slow-zhang

so running the last test with code that skips checking the json Marshalling, I get:

  "definitions": {
    "restfulspec.Child": {
      "required": [
        "FieldA",
        "FieldB"
      ],
      "properties": {
        "FieldA": {
          "$ref": "#/definitions/restfulspec.Parent"
        },
        "FieldB": {
          "type": "integer",
          "format": "int32"
        }
      }
    },
    "restfulspec.Parent": {
      "required": [
        "FieldA"
      ],
      "properties": {
        "FieldA": {
          "type": "string"
        }
      }
    }
  }
}

emicklei avatar Sep 28 '23 20:09 emicklei