apple / swift-openapi-generator

Generate Swift client and server code from an OpenAPI document.
https://swiftpackageindex.com/apple/swift-openapi-generator/documentation
Apache License 2.0
1.21k stars 87 forks source link

Default responses lead to invalid Swift code #530

Closed pepicrft closed 1 month ago

pepicrft commented 3 months ago

Description

When using default responses in the OpenAPI schema, the generated code for the client places the default case at the top of the switch, and the compiler yields an error Additional 'case' blocks cannot appear after the 'default' block of a 'switch'.

Reproduction

openapi: "3.0.3"
info:
  title: API
  version: 0.1.0
paths:
  /api/projects:
    get:
      operationId: listProjects
      responses:
        default:
          description: Unexpected error
          headers:
            X-Request-Id:
              schema:
                type: string
              description: The id of the request that led to this response.
        "200":
          description: A success response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Projects"

Package version(s)

├── tuist<https://github.com/tuist/tuist@unspecified>
│   ├── swift-argument-parser<https://github.com/apple/swift-argument-parser@1.3.0>
│   ├── swift-log<https://github.com/apple/swift-log@1.5.3>
│   ├── swift-tools-support-core<https://github.com/apple/swift-tools-support-core@0.6.1>
│   │   └── swift-system<https://github.com/apple/swift-system.git@1.2.1>
│   ├── combineext<https://github.com/CombineCommunity/CombineExt@1.8.1>
│   ├── queuer<https://github.com/FabrizioBrancati/Queuer@2.1.1>
│   ├── anycodable<https://github.com/Flight-School/AnyCodable@0.6.7>
│   ├── zipfoundation<https://github.com/weichsel/ZIPFoundation@0.9.18>
│   ├── keychainaccess<https://github.com/kishikawakatsumi/KeychainAccess@4.2.2>
│   ├── stencil<https://github.com/stencilproject/Stencil@0.15.1>
│   │   ├── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │   │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   ├── graphviz<https://github.com/SwiftDocOrg/GraphViz@0.2.0>
│   ├── stencilswiftkit<https://github.com/SwiftGen/StencilSwiftKit@2.10.1>
│   │   ├── komondor<https://github.com/shibapm/Komondor.git@1.1.3>
│   │   │   ├── packageconfig<https://github.com/shibapm/PackageConfig.git@1.1.3>
│   │   │   └── shellout<https://github.com/JohnSundell/ShellOut.git@2.3.0>
│   │   └── stencil<https://github.com/stencilproject/Stencil@0.15.1>
│   │       ├── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │       │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │       └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   ├── swiftgen<https://github.com/SwiftGen/SwiftGen@6.6.2>
│   │   ├── swift-argument-parser<https://github.com/apple/swift-argument-parser@1.3.0>
│   │   ├── yams<https://github.com/jpsim/Yams.git@5.0.6>
│   │   ├── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │   │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   ├── stencil<https://github.com/stencilproject/Stencil@0.15.1>
│   │   │   ├── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │   │   │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   ├── stencilswiftkit<https://github.com/SwiftGen/StencilSwiftKit@2.10.1>
│   │   │   ├── komondor<https://github.com/shibapm/Komondor.git@1.1.3>
│   │   │   │   ├── packageconfig<https://github.com/shibapm/PackageConfig.git@1.1.3>
│   │   │   │   └── shellout<https://github.com/JohnSundell/ShellOut.git@2.3.0>
│   │   │   └── stencil<https://github.com/stencilproject/Stencil@0.15.1>
│   │   │       ├── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │   │       │   └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   │       └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   │   └── kanna<https://github.com/tid-kijyun/Kanna.git@5.2.7>
│   ├── xcodeproj<https://github.com/tuist/XcodeProj@8.18.0>
│   │   ├── aexml<https://github.com/tadija/AEXML.git@4.6.1>
│   │   └── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│   │       └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
│   ├── xcbeautify<https://github.com/cpisciotta/xcbeautify@1.4.0>
│   │   ├── swift-argument-parser<https://github.com/apple/swift-argument-parser@1.3.0>
│   │   ├── colorizer<https://github.com/getGuaka/Colorizer.git@0.2.1>
│   │   └── xmlcoder<https://github.com/MaxDesiatov/XMLCoder.git@0.17.1>
│   ├── difference<https://github.com/krzysztofzablocki/Difference.git@1.0.2>
│   └── mockable<https://github.com/Kolos65/Mockable.git@0.0.2>
│       └── swift-syntax<https://github.com/apple/swift-syntax.git@509.1.1>
├── swift-tools-support-core<https://github.com/apple/swift-tools-support-core@0.6.1>
│   └── swift-system<https://github.com/apple/swift-system.git@1.2.1>
├── swift-argument-parser<https://github.com/apple/swift-argument-parser@1.3.0>
├── swift-openapi-runtime<https://github.com/tuist/swift-openapi-runtime@unspecified>
├── swift-openapi-urlsession<https://github.com/tuist/swift-openapi-urlsession@unspecified>
│   └── swift-openapi-runtime<https://github.com/tuist/swift-openapi-runtime@unspecified>
├── xcodeproj<https://github.com/tuist/XcodeProj@8.18.0>
│   ├── aexml<https://github.com/tadija/AEXML.git@4.6.1>
│   └── pathkit<https://github.com/kylef/PathKit.git@1.0.1>
│       └── spectre<https://github.com/kylef/Spectre.git@0.10.1>
├── swiftecc<https://github.com/leif-ibsen/SwiftECC@4.0.0>
│   ├── bigint<https://github.com/leif-ibsen/BigInt@1.14.0>
│   └── asn1<https://github.com/leif-ibsen/ASN1@2.2.0>
│       └── bigint<https://github.com/leif-ibsen/BigInt@1.14.0>
├── cryptoswift<https://github.com/krzyzanowskim/CryptoSwift@1.8.0>
├── mockable<https://github.com/Kolos65/Mockable.git@0.0.2>
│   └── swift-syntax<https://github.com/apple/swift-syntax.git@509.1.1>
└── swifter<https://github.com/httpswift/swifter.git@unspecified>

Expected behavior

I'd expect the default to be at the bottom.

Environment

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0

Additional information

No response

czechboy0 commented 3 months ago

The generated code respects the order specified in your OpenAPI document.

Let me take a look though, we should at least move the default case to the end.

A temporary workaround is to move the default case in the OpenAPI doc.

czechboy0 commented 3 months ago

Well we already have some logic to try to do this, but if you're seeing it not work, then it's likely broken.

https://github.com/apple/swift-openapi-generator/blob/main/Sources/_OpenAPIGeneratorCore/Translator/Operations/OperationDescription.swift

If you'd like to open a PR fixing this that'd be much appreciated 🙏

pepicrft commented 2 months ago

Hey @czechboy0 👋🏼 Thanks for looking into it. I'll go ahead and open a PR :)

czechboy0 commented 1 month ago

@pepicrft So I think you might be using an outdated fork here?

├── swift-openapi-runtime<https://github.com/tuist/swift-openapi-runtime@unspecified>
├── swift-openapi-urlsession<https://github.com/tuist/swift-openapi-urlsession@unspecified>

I just tested your snippet on main and it works correctly. Also thanks @mt-hodaka for adding a snippet test in #554.

Please reopen the issue if you can still reproduce it on the latest version, thanks!