Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Questions re: anyOf/allOf/oneOf, and one more thing #534

Open
edonv opened this issue Feb 29, 2024 · 5 comments
Open

Questions re: anyOf/allOf/oneOf, and one more thing #534

edonv opened this issue Feb 29, 2024 · 5 comments
Labels
kind/support Adopter support requests. status/triage Collecting information required to triage the issue.

Comments

@edonv
Copy link

edonv commented Feb 29, 2024

Question

I'm sure there are details I'm unaware of that impact these things, so forgive me if this has been discussed before. I have a few questions/thoughts regarding anyOf/allOf/oneOf:

  • Could oneOf be translated to an enum with associated values of the possible options?

  • For anyOf/oneOf where the only options are "null" and some $ref, could it be translated to an optional instance of that type? Because as of now, it's this:

struct itemPayload: Codable, Hashable, Sendable {
    var value1: OpenAPIRuntime.OpenAPIValueContainer?
    var value2: Components.Schemas.NamedAPIResource?
}

from this:

"item": {    
    "anyOf": [
        {
            "type": "null"
        },
        {
            "$ref": "./NamedAPIResource.json"
        }
    ]
}

when it would ideally just be:

typealias itemPayload: Components.Schemas.NamedAPIResource?

Separately, is it possible to set the configuration so the generated types from components/schemas are public, but the initializers and underlying stuff is internal? Or would I just have to do 2 separate targets that generate the types and clients separately, then I combine them for public-facing stuff in a 3rd target?

@edonv edonv added kind/support Adopter support requests. status/triage Collecting information required to triage the issue. labels Feb 29, 2024
@czechboy0
Copy link
Collaborator

Hi @edonv,

yeah this is a large topic, so let me answer the individual points inline.

Regarding nullability, check out this maintainer doc (https://swiftpackageindex.com/apple/swift-openapi-generator/1.2.1/documentation/swift-openapi-generator/handling-nullable-schemas), which goes into detail of some of the decisions we made and hopefully answers your question.

At a higher level - we try to apply the smallest amount of post-processing to the OpenAPI doc, we don't flatten various schemas, because we want to stay faithful to the doc (rationale explained here: https://swiftpackageindex.com/apple/swift-openapi-generator/1.2.1/documentation/swift-openapi-generator/project-scope-and-goals).

That means that if you write something like:

Foo:
  type: object
  properties:
    bar:
      anyOf:
        - type: null
        - type: string

we will generate the complicated structure, even though you could have spelled the same thing as:

Foo:
  type: object
  properties:
    bar:
      type: string

The idea is that the OpenAPI document is the source of truth, and we follow that as closely as possible. If your OpenAPI document is written in an inefficient or verbose way, so will your generated Swift code.

Could oneOf be translated to an enum with associated values of the possible options?

That's already the case today. If you're not seeing that, please provide an example of the input OpenAPI snippet and generated code.

For anyOf/oneOf where the only options are "null" and some $ref, could it be translated to an optional instance of that type?

Not really, for the reasons explained earlier - we don't try to optimize your OpenAPI doc, that's up to the OpenAPI doc author. We just generate the most faithful Swift representation of the OpenAPI doc, without first pre-processing it.

If you're looking for ways to find and fix inefficiencies, there are many OSS tools that take an OpenAPI document as input and suggest improvements. But that functionality is out of scope of our Swift code generator, we try to be good OpenAPI community citizens and not needlessly include too many features that are already covered by other tools, as it both increases complexity of the generator and removes flexibility from our adopters.

@czechboy0 czechboy0 changed the title Questions re: anyOf/allOf/oneOf`, and one more thing Questions re: anyOf/allOf/oneOf, and one more thing Mar 1, 2024
@czechboy0 czechboy0 changed the title Questions re: anyOf/allOf/oneOf, and one more thing Questions re: anyOf/allOf/oneOf, and one more thing Mar 1, 2024
@edonv
Copy link
Author

edonv commented Mar 4, 2024

Thanks for the detailed answer. I'm still relatively new to OpenAPI as it is, so it's likely just that the doc I'm working on isn't as efficient as it could be, leading the generated Swift code to be the same.

But in that vein, in OpenAPI, what would you say would be the best way to represent a property in an object that must be present but can be null? It sounds like there should be a better way than what I example above.

@edonv
Copy link
Author

edonv commented Mar 4, 2024

And any suggestions regarding my last question?

Separately, is it possible to set the configuration so the generated types from components/schemas are public, but the initializers and underlying stuff is internal? Or would I just have to do 2 separate targets that generate the types and clients separately, then I combine them for public-facing stuff in a 3rd target?

@simonjbeaumont
Copy link
Collaborator

And any suggestions regarding my last question?

Separately, is it possible to set the configuration so the generated types from components/schemas are public, but the initializers and underlying stuff is internal? Or would I just have to do 2 separate targets that generate the types and clients separately, then I combine them for public-facing stuff in a 3rd target?

That's currently the only supported way, yes. Our integration test package has an example of using the generator in multiple targets to separate the generation of types, client, and server, and sharing the generated types in the other targets: https://github.com/apple/swift-openapi-generator/tree/main/IntegrationTest.

@czechboy0
Copy link
Collaborator

But in that vein, in OpenAPI, what would you say would be the best way to represent a property in an object that must be present but can be null?

That's not easy to do for the reasons outlined in: #513 (comment)

I'd recommend to try to avoid needing to make a distinction between a present null value and an absent value, if at all possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/support Adopter support requests. status/triage Collecting information required to triage the issue.
Projects
None yet
Development

No branches or pull requests

3 participants