cue-lang / cue

The home of the CUE language! Validate and define text-based and dynamic configuration
https://cuelang.org
Apache License 2.0
5.14k stars 294 forks source link

Embedding breaks openapi-generator.tech code generation in different ways because of how all_of is used? #1498

Open greglearns opened 2 years ago

greglearns commented 2 years ago

What version of CUE are you using (cue version)?

cue version v0.4.1 darwin/amd64

Does this issue reproduce with the latest release?

Unknown

What did you do?

openapi-generator.tech (the main way that people do OpenAPI3.0 code-generation?) has a problem with CUE’s openapi output when #Models are combined. This CUE:

#One:{ field1: string, #Two}
#Two: { field2: string }

…generates this OpenAPI3.0

"One": {
  "type": "object",
  "properties": { "field1": { "type": "string" }
  },
  "allOf": [
    { "$ref": "#/components/schemas/Two" },
    { "required": [ "field1" ] }
  ]
}

but in openapi-generator, it thinks that One's field1 and field2 are OPTIONAL (they should be REQUIRED).

What did you expect to see?

One's field1 and field2 should both be REQUIRED.

What did you see instead?

One's field1 and field2 are both interpreted as OPTIONAL.

OTHER EXAMPLE

#One:{ field1: string, { field2: string }}

... produces this OpenAPI 3.0 schema:

{
  "One": {
    "type": "object",
    "properties": {
      "field2": { "type": "string" },
      "field1": { "type": "string" }
    },
    "allOf": [
      { "required": [ "field2" ] },
      { "required": [ "field1" ] }
    ]
  }
}

... which openapi-generator.tech interprets field1 and field2 as OPTIONAL when they should be REQUIRED.

Copying the fields from #Two into #One is a bummer:

#One:{ field1: string, field2: string }

... generates this OpenAPI 3.0 code:

{
  "One": {
    "type": "object",
    "required": [ "field1", "field2" ],
    "properties": {
      "field1": { "type": "string" },
      "field2": { "type": "string" }
    }
  }
}

... which works as expected: field1 and field2 are both REQUIRED, as expected. But now we have 2 copies of the fields.

Another way that breaks in a different way with references to sum types (enumerations)

#One:{
  field1: #Id,
  if true { #Two}
}
#Two: { field2: string }
#Id: 1 | 2

The property for field1 adds a $ref (good) but also adds a type: int (bad) instead of saying it is a sum-type/enumeration.

P.S.: THANK YOU so much for making CUE! CUE is awesome!

rogpeppe commented 2 years ago

@greglearns thanks for the report! At first glance the generated OpenAPI spec looks reasonable to me.

For the first two examples you mention, would it be accurate to characterise this as a shortcoming of the openapi-generator.tech generator rather than a CUE bug?

For the last example, CUE doesn't seem to generate any spec at all, which seems like it's a probably a bug.

A testscript reproducer:

exec cue export --out yaml+openapi x.cue
cmp stdout expect-stdout
-- x.cue --
#One:{
    field1: #Id,
    if true { #Two}
}
#Two: { field2: string }
#Id: 1 | 2
-- expect-stdout --

This shows that the OpenAPI output looks like this:

openapi: 3.0.0
info:
  title: Generated by cue.
  version: no version
paths: {}
components:
  schemas: {}

but I'd expect to see some schema components in that output. I've just raised a separate issue for that (https://github.com/cue-lang/cue/issues/1643); let's focus this issue on the first two examples.