go-swagger / go-swagger

Swagger 2.0 implementation for go
https://goswagger.io
Apache License 2.0
9.48k stars 1.25k forks source link

Generate map[string]json.RawMessage model #1879

Open sidh opened 5 years ago

sidh commented 5 years ago

What is the correct way to generate map[string]json.RawMessage model?

x-go-type does not work in this case:

type: object
additionalProperties:
  type: object
  x-go-type:
  import:
    alias: "json"
    package: "encoding/json"
  type: "RawMessage"

but does work in this

type: object
additionalProperties:
  allOf:
  - type: object
    x-go-type:
    import:
      alias: "json"
      package: "encoding/json"
    type: "RawMessage"

but generates an unneeded type that holds json.RawMessage.

fredbi commented 5 years ago

Could you please post the generated model and point out what is wrong with it? Thanks.

sidh commented 5 years ago

The desired type is map[string]json.RawMessage.

For the first case it generates map[string]interface{}.

For the second case it generates map[string]MyTypeAnon with

type MyTypeAnon struct {
  json.RawMessage
}
fredbi commented 5 years ago

First case looks like a bug. Second case is expected, since the allOf makes a new type.

sidh commented 5 years ago

Agree on the second case. First case is probably a bug, yes.

Also it seems x-go-type does not work with properties of an object:

MyType:
  type: object
  properties:
    prop:
      type: object
      x-go-type:
        import:
          alias: "json"
          package: "encoding/json"
        type: "RawMessage"

results in

type MyType struct {
  Prop interface{}
}

instead of

type MyType struct {
  Prop json.RawMessage
}
fredbi commented 5 years ago

Yes. I just checked in here: x-go-type extension is currently only accounted for definitions, not nested structures. So this is not a bug, but a (limited) feature... :)

I don't think this feature was created in the first place for this use case of hijacking type mappings inside definitions.

A hacky way to go could be to change the type mapping, like defined here and define or redefine some format to map as json.RawMessage.

sidh commented 5 years ago

A hacky way to go could be to change the type mapping, like defined here and define or redefine some format to map as json.RawMessage.

This solution will work too. May be thats the correct way to go?

fredbi commented 5 years ago

it is not supported atm but you may still experiment locally based on this. I am not sure about how we could integrate this with a PR while making sure it is not breaking anything.

Some days ago, I was reflecting on a similar problem about optionally mapping binary format as []byte rather than the default io.ReadCloser. I feel this is a related theme.

casualjim commented 5 years ago

Some days ago, I was reflecting on a similar problem about optionally mapping binary format as []byte rather than the default io.ReadCloser. I feel this is a related theme.

We can never do that because you lose the ability to support a very important use case. You can easily go from slice to stream but you can't do that the other way around and guarantee the code will still function

@sidh you can use format: byte for a string, that's the closest you can get to what you want to do Or make a type with a custom marshaler

sidh commented 5 years ago

I initially wanted to dynamically handle part of JSON and for that I need json.RawMessage as simple format:byte will expect just bytes, not real JSON.

timbunce commented 5 years ago

Related to #1622.

Crypto89 commented 5 years ago

I ran into the same problem, as a work around this seems to work:

definitions:
  event:
    type: object
    properties:
      id:
        type: string
      data:
        ref: '#/definitions/data'
  data:
    type: object
    x-go-type:
      import:
        alias: "json"
        package: "encoding/json"
      type: "RawMessage"

and this generates the following code:

// Event event
// swagger:model event
type Event struct {

    // data
    Data json.RawMessage `json:"data,omitempty"`

    // id
    // Required: true
    ID *string `json:"id"`