CUE export openapi+yaml format not resolving references correctly
What version of CUE are you using (cue version)?
0.11.0
Does this issue reproduce with the latest stable release?
Yes
What did you do?
Tried to export the following minimal CUE file as an example
// test.cue
#TestBaseComponent : {
propABase: string
}
#TestParentComponent: {
propAParent: string
testChild: #TestBaseComponent & {
propABase: propAParent
}
}
using command cue export .\test.cue --out openapi+yaml
What did you expect to see?
I expected that the propABase in the definition would be a string not a ref type
What did you see instead?
See the invalid syntax $ref: '#/components/schemas/TestParentComponent.propAParent' below
openapi: 3.0.0
info:
title: Generated by cue.
version: no version
paths: {}
components:
schemas:
TestBaseComponent:
type: object
required:
- propABase
properties:
propABase:
type: string
TestParentComponent:
type: object
required:
- propAParent
- testChild
properties:
propAParent:
type: string
testChild:
type: object
properties:
propABase:
$ref: '#/components/schemas/TestParentComponent.propAParent'
allOf:
- $ref: '#/components/schemas/TestBaseComponent'
- required:
- propABase
Could you please explain why you expect propABase to be a string type rather than a reference? In the original CUE it does use a reference to propAParent, so the current output seems fine to me.
What I mean is that the generated output is an invalid openAPI spec (which seems like it shouldn't be allowed?). As far as I understand, $ref: '#/components/schemas/TestParentComponent.propAParent is invalid because you need to point to a schema object and not a property. At least it was invalid for the tooling that was consuming the generated output (redocly).
Ah I see, thanks for the clarification. I'll let @rogpeppe chime in.
There are a couple of issues I'd highlight here.
Firstly, the generated reference is just incorrect: a period is not a valid separator in JSON Pointer, and the actual position of the properties is inside the properties object, so the reference would be more correctly written as #/components/schemas/TestParentComponent/properties/propAParent.
Secondly, the original schema implies that propABase is the same as propAParent, but it's not actually possible for OpenAPI to express that constraint.
In general, I don't think it's a good idea to produce schemas that refer to non-definition objects, so I'd say that the most appropriate fix here is either to generate an independent definition and refer to that within both TestParentComponent and from TestBaseComponent, or to generate independent definitions for both.
The first approach might look like:
openapi: 3.0.0
info:
title: Generated by cue.
version: no version
paths: {}
components:
schemas:
TestBaseComponent:
type: object
required:
- propABase
properties:
propABase:
type: string
TestParentComponent:
type: object
required:
- propAParent
- testChild
properties:
propAParent:
$ref: "#/components/schemas/TestParentComponent.propAParent"
testChild:
type: object
properties:
propABase:
$ref: '#/components/schemas/TestParentComponent.propAParent'
allOf:
- $ref: '#/components/schemas/TestBaseComponent'
- required:
- propABase
TestParentComponent.propAParent:
type: string
The second might look like this:
openapi: 3.0.0
info:
title: Generated by cue.
version: no version
paths: {}
components:
schemas:
TestBaseComponent:
type: object
required:
- propABase
properties:
propABase:
type: string
TestParentComponent:
type: object
required:
- propAParent
- testChild
properties:
propAParent:
type: string
testChild:
type: object
properties:
propABase:
type: string
allOf:
- $ref: '#/components/schemas/TestBaseComponent'
- required:
- propABase
In this particular case, the second might seem more attractive, but that might not seem so if there ends up with significant duplication between the two sites.
For the record, this is a contrived definition to demonstrate the point that an invalid spec was produced. In the real definition that it was inspired from, I was able to get around the issue after taking a step back and redefining things to split out the constraints from the implementation similar to what you've suggested. However I thought I'd at least highlight that it seems possible to produce valid CUE that results in invalid OpenAPI spec.
Indeed, and thank you for filing the issue!