-
Notifications
You must be signed in to change notification settings - Fork 126
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
[Generator] Multiple content types support #146
[Generator] Multiple content types support #146
Conversation
[Generator] Design away EncodableBodyContent ### Motivation See apple/swift-openapi-runtime#30 Depends on Runtime 0.1.6 ### Modifications Adapted the generator code for the runtime changes. Also, since this was factored out of the big PR (#146) adding multiple content types, you can see the code was prepared for handling multiple content types, even though still in this PR it only ever gets N=1. ### Result The generated code uses the new simplified runtime functions, and prepares us for multiple content types. ### Test Plan Adapted file-based reference tests to generate the new syntax. Reviewed by: simonjbeaumont Builds: ✔︎ pull request validation (5.8) - Build finished. ✔︎ pull request validation (5.9) - Build finished. ✔︎ pull request validation (docc test) - Build finished. ✔︎ pull request validation (integration test) - Build finished. ✔︎ pull request validation (nightly) - Build finished. ✔︎ pull request validation (soundness) - Build finished. #152
[NFC] Refactor PetstoreConsumerTests to allow multiple versions ### Motivation In upcoming features that contain breaking changes, but we'll stage them in behind a feature flag, we'd like to have multiple variants of the `PetstoreConsumerTests` test target, allowing us to test both the existing behavior and the new behavior once a feature flag is enabled. These additional variants would be temporary, and would be deleted again (or rather, the main test suite would be updated) once the feature flag is enabled unconditionally. So the steady state number of `PetstoreConsumerTest` variants would continue to be 1, just for short periods of time, it might be higher. ### Modifications This PR makes that possible by refactoring common functionality into a new internal target `PetstoreConsumerTestCore`. Note that all the variants of the test target share the same OpenAPI document, but generate different variants of the reference code. Highlights: - new `PetstoreConsumerTestCore` target, depended on by the existing `PetstoreConsumerTests` - added an ability to _not_ fail the test when specific diagnostics are emitted (through the new `ignoredDiagnosticMessages: Set<String>` parameter), which allows us to test both existing and new behavior on the same OpenAPI document. Other, non-allowlisted diagnostics, still continue to fail the test, so new ones won't sneak through undetected. - many test functions now optionally take `featureFlags` and `ignoredDiagnosticMessages`, again allowing us to test both existing and proposed behavior hidden behind a feature flag ### Result It will be a lot easier to temporarily introduce other variants of the `PetstoreConsumerTests` test target to allow for thoroughly testing features even before they are enabled by default, giving us more confidence in the accuracy of proposals and their associated implementations. ### Test Plan All tests continue to pass, this is an NFC, a pure refactoring, making the next PR much smaller. To see how this all fits together, check out the PR that has all the changes: #146. That said, these partial PRs are easier to review, as they're each focused on one task. Reviewed by: gjcairo, simonjbeaumont Builds: ✔︎ pull request validation (5.8) - Build finished. ✔︎ pull request validation (5.9) - Build finished. ✔︎ pull request validation (docc test) - Build finished. ✔︎ pull request validation (integration test) - Build finished. ✔︎ pull request validation (nightly) - Build finished. ✔︎ pull request validation (soundness) - Build finished. #157
Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift
Outdated
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Translator/RequestBody/TypedRequestBody.swift
Show resolved
Hide resolved
Tests/PetstoreConsumerTests_FF_MultipleContentTypes/TestClient.swift
Outdated
Show resolved
Hide resolved
Before digging into the review proper, thought I'd pick up on this question:
I think it's reasonable for us to throw an error if |
Trying all of them is another option, yeah. Although if the first content type is a binary type, we'll never fail to parse as it, and move to the next one. But if it's ordered from the most to least restrictive, this would work well. One concern about this would be performance, as trying to parse large (e.g. image) data as JSON might be slow, but if it still "works", the adopter might not know they should probably go and fix their server or OpenAPI doc. So, to recap our options:
|
…g/unwrapping bodies
def5585
to
bcdbcd5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking the time to rebase this PR for easier review. It's looking really good. I've added a few questions, otherwise I think it's looking really good!
Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift
Outdated
Show resolved
Hide resolved
...ratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Client.swift
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift
Outdated
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift
Outdated
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Translator/RequestBody/TypedRequestBody.swift
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Layers/StructuredSwiftRepresentation.swift
Outdated
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift
Outdated
Show resolved
Hide resolved
Sources/_OpenAPIGeneratorCore/Translator/RequestBody/translateRequestBody.swift
Show resolved
Hide resolved
Answering this question from the description: I think this is reasonable. The only alternative is to send supported ones, I guess, but I'm not sure what benefit this would have over sending just the first one. |
…r chosen content types
[Runtime] Multiple content types support Runtime changes for apple/swift-openapi-generator#146 ### Motivation See apple/swift-openapi-generator#146 for motivation. ### Modifications Adds new methods for: - `extractContentTypeIfPresent` - returns the `content-type` header - `isValidContentType` - evaluates content type equivalence, including wildcards - `makeUnexpectedContentTypeError` - returns an error that the generated code can throw Deprecates this method, which will be removed in a future breaking version: - `validateContentTypeIfPresent` - only made sense when we supported only 1 content type value for a body ### Result Enables generated code to support multiple content types. ### Test Plan Deprecated the tests for the deprecated method, and added unit tests for the new methods. Reviewed by: gjcairo, simonjbeaumont Builds: ✔︎ pull request validation (5.8) - Build finished. ✔︎ pull request validation (5.9) - Build finished. ✔︎ pull request validation (api breakage) - Build finished. ✔︎ pull request validation (docc test) - Build finished. ✔︎ pull request validation (integration test) - Build finished. ✔︎ pull request validation (nightly) - Build finished. ✔︎ pull request validation (soundness) - Build finished. #29
Depends on apple/swift-openapi-runtime#29
Motivation
Up until now, when an OpenAPI document contained more than one content type in either a request or a response body, we would only generate code for now, and ignored the other ones.
However, that was a temporary workaround until we could add proper support for multiple content types, which is what this PR is about.
Addresses #6 and #7, except for the "Accept header" propagation, which will be addressed separately and have its own PR and even a proposal. That's one of the reasons this feature is landing disabled, hidden behind the
multipleContentTypes
feature flag.A tip for reviewing this change: first check out how the test OpenAPI document and the reference files changed, that shows the details of how we encode and decode multiple content types. I also added comments in the code for easier review.
Modifications
content
map in request and response bodies are now generated in theBody
enum.supportedTypedContents
that returns all supported content types, used now instead of thebestTypedContent
method we used before. What is a "supported" content type? One that has a schema that doesn't returnfalse
toisSchemaSupported
. (This is a pre-existing concept.)Open Questions
content-type
header is provided? Previously, with up to 1 content type support, we still went ahead and tried to parse it. But here, we don't know which content to parse it as, so we just try it with the first in the list (we respect the order in the YAML dictionary, so what the user put first will be what we try to use when nocontent-type
header is provided). If an invalidcontent-type
value is provided, we throw an error (pre-existing behavior). Q: Is choosing the first reasonable? What would be better? Note that, unfortunately, many servers don't sendcontent-type
today.Result
When an adopter provides multiple content types in their OpenAPI document, we generate one case in the Body enum for each! However, the new functionality is disabled by default, has to be explicitly requested by enabling the
multipleContentTypes
feature flag either on the CLI or in the config file.Test Plan
Added
setStats
andgetStats
operations that employ multiple content types, one in a request body, the other in a response body. Added unit tests for it inPetstoreConsumerTests
to verify it all works correctly at runtime.Deleted
Tests/OpenAPIGeneratorCoreTests/Translator/RequestBody/Test_translateRequestBody.swift
as snippet tests do this job better, and I didn't want to spend the time updating the test.Adds
PetstoreConsumerTests_FF_MultipleContentTypes
, a variant ofPetstoreConsumerTests
for when themultipleContentTypes
feature flag is enabled, so we test both how the existing logic handles multiple content types (it picks one), and the new logic (it generates code for all supported ones it found).TODOs
IfConditionPair
toIfBranch
if
from the subsequenceelse if
s inIfStatement
, to 3 properties: first if, then an array of else ifs, then an optional else; to avoid creating invalid codeContentType
to avoid repeatedly parsing the received content type