-
Notifications
You must be signed in to change notification settings - Fork 124
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
Support $dynamicAnchor
and $dynamicRef
#547
Comments
Thanks @brandonbloom - I'll mark this one as blocked, until the OpenAPIKit support is landed. |
I wonder, have you also considered generating generic types, instead of protocols? From my reading of the specification, that might be the closest representation in Swift to the requested feature. |
I've begun exploring this in OpenAPIKit. I've only thought on it for a few minutes so far, but I wanted to make sure to extend an invitation for help deciding how to integrate these new references into OpenAPKit if anyone over here has thoughts; I know it isn't always possible to comment directly on third party repositories, I will do my best to coordinate any conversation that happens split between the two disparate GitHub issues. My initial thinking is I cannot simply support an additional key and boolean property on the |
I wonder what the minimum support for a generic type would be here. Basically, knowing that a type is generic over N types, and OpenAPIKit filling them in. Re references, in 3.1 there's OpenAPI.Reference, maybe that's where some of it could be added? |
OpenAPI.Reference may not quite fit the needs here since that type wraps a reference and adds description/summary overriding; it does manage to introduce different behavior compared to JSONReference, but since it was introduced to support the OpenAPI-specific extensions to |
Fair enough - yeah maybe a way to make progress here would be to first identify the minimum work needed to support the simple |
@brandonbloom do you have an example or two of OpenAPI documents that take advantage of |
I considered it briefly & perhaps discarded it prematurely. The reasons I was immediately drawn to protocols is because generics use positional type parameters, which don't have a clean mapping to the dynamicRef concept as far as I can tell. Associatedtypes seem more similar to what the local $defs look like.
Examples from Github: https://github.com/search?q=%28%22%24dynamicRef%22+OR+%22%24dynamicAnchor%22%29+%28path%3A**%2F*.yaml+OR+path%3A**%2F*.yml+OR+path%3A**%2F*.json%29&type=code |
I was moreso curious if you had examples that motivated you to request the feature; if it turns out that OpenAPIKit support for dynamic reference use-cases does not come all at once, I'd like to prioritize support for those situations that are most pressing for consumers of OpenAPI documents (as opposed to json-schema more broadly). It's fine if not. |
In that vein, I have begun to brainstorm what exactly OpenAPIKit tells a consumer beyond "here's a dynamic reference." That's the bare minimum (and net addition to OpenAPIKit): Parsing That leads me to the question of what non-referential representation would be most helpful to the Swift generator. One potential answer is that OpenAPIKit could surface the In reality, dynamic anchors do not always have It's possible this idea is flawed because there's no inherent need to uniquely and globally identify dynamically referenced schemas: if you are actively crawling the json-schema and tracking the dynamic context, you don't need globally unique you just need to look at the current local dynamic context. Another idea is OpenAPIKit could surface that dynamic context as easily accessible for any given |
I'm using it in a schema I'm developing. The simplest example is that I have a generic-type for a pagination container. In TypeScript notation: type Page<Item> = {
items: Item[];
next: string | null;
} This is then parameterized by each type of resource I'm returning, something like: type FriendPage = Page<Friend>; I already generate my schemas programmatically, so I'm working around the lack of support for this feature by treating generic types like macros and expanding them template-programming style. Since my schema generation is already parameterized, I can emit dynamic refs/anchors for validators that support them and then erase the generic types and emit specialized schemas as needed for other output targets.
Although it also does not yet support dynamic refs/anchors, a newer Go library for OpenAPI specs has a two-level model: https://pb33f.io/libopenapi/model/ -- This roughly corresponds to a concrete parse tree and an abstract document object model. I'm not sure if that maps to your design at all, but that seems natural to me. |
That's good context, @brandonbloom - let's focus on this simple example first: generic pages. @mattpolzin what's the first version of your approach you could see supporting this? I'd prefer us to build this incrementally, based on real-world needs. |
I've got work ahead of me just to properly represent This is what lead me to the questions I posed above in #547 (comment). |
FWIW, we fully support recursive schemas in Swift OpenAPI Generator today, so I'd like for that to continue even with this feature. You're right that we should consider it now, instead of fully specializing on the example use case. |
It may help me to get the 10,000 ft view of how the generator handles other existing recursive cases it already handles -- for one thing, to help me understand where division of labor will happen for this new feature, so I am not trying to solve problems that the Swift Generator will want to write its own code for anyway. Would you be able to link me to the relevant code and possibly give me any description you think might help me grok it quickly? I don't have time to become an expert in the whole generator codebase, so trying to be pragmatic 😄 |
Sure, please check this out first, and I can answer any followups: https://swiftpackageindex.com/apple/swift-openapi-generator/1.2.1/documentation/swift-openapi-generator/supporting-recursive-types |
Thanks. Even easier than reading the code! So, I am thinking that the easiest path forward is possibly for OpenAPIKit to facilitate the swift generator using roughly the same code (at the very least the same strategy) as it uses today to handle recursion via Components lookup to also handle dynamic references. Dynamic references may also lead to recursion just like regular references, so the difference of course is that dynamic references change depending on where in the schema they live. So, today OpenAPIKit offers a lookup function on Components that allows resolving non-dynamic local references. Newly needed is a lookup function that handles dynamic refs. That's already an interesting problem to consider (looking forward to thinking on it) because OpenAPI documents kind of have two different potential contexts to consider: there's the immediate json-schema context and its I think this is where I want to get to first in OpenAPIKit: parse/serialize/export dynamic refs and anchors and expose a lookup function that behaves much like the current one but understands dynamic context and can find anchors as well as local paths. There's no small chunk of work there because in addition to the dynamic context being new we've previously not needed to handle While I am working on that, which feels like important foundation, we can continue to discuss what gaps are left RE the swift generator's eventual goals. Maybe that's enough for the swift generator to handle the rest, or maybe OpenAPIKit also exposes some form of "give me all the ways this ref could resolve in the document" function a la the question of what possible specializations a generic type can have. |
This sounds in line with what I was thinking, @mattpolzin. I'm happy to wait for the foundational pieces to land in OpenAPIKit, and then try to integrate them in the generator, and if we feel there are additional conveniences needed, we can take it from there. |
FYI, there might be further changes in the upcoming OpenAPI v4: https://www.openapis.org/blog/2023/12/06/openapi-moonwalk-2024 |
Motivation
These keywords are defined in the JSON Schema 2020-12 dialect.
Release notes: https://json-schema.org/draft/2020-12/release-notes
These are useful for representing generics: https://json-schema.org/blog/posts/dynamicref-and-generics
Specification of dynamic scope rules: https://json-schema.org/draft/2020-12/json-schema-core#name-lexical-scope-and-dynamic-s
Proposed solution
Schemas containing
$defs
generate types that include the defs as members. If the schemas contain$dynamicAnchor
, they create protocols with associated types instead of concrete types with type aliases. The schema of the dynamic-anchored types are used as the type constraint for the associated types.Dynamic reference schemas (those containing the
$dynamicRef
keyword) refer to associated types and may supply generic parameters using their own$defs
and$dynamicAnchor
keywords.Alternatives considered
Avoid generating protocols / associated types, and instead always generate concrete types, treating dynamic refs/anchors as template instantiation.
Additional information
This would depend on support in OpenAPIKit. Upstream issue filed: mattpolzin/OpenAPIKit#359
The text was updated successfully, but these errors were encountered: