From 355538fcd869d43a455aebc313f70a795301ac21 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Fri, 8 Sep 2023 15:00:10 +0200 Subject: [PATCH 1/6] [Proposal] SOAR-0005: Adopting the Swift HTTP Types package --- .../Documentation.docc/Proposals/Proposals.md | 1 + .../Documentation.docc/Proposals/SOAR-0005.md | 213 ++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/Proposals.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/Proposals.md index 8111e5a9..8323778a 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/Proposals.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/Proposals.md @@ -46,3 +46,4 @@ If you have any questions, tag [Honza Dvorsky](https://github.com/czechboy0) or - - - +- diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md new file mode 100644 index 00000000..4aed5d8f --- /dev/null +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -0,0 +1,213 @@ +# SOAR-0005: Adopting the Swift HTTP Types package + +Adopt the new ecosystem-wide Swift HTTP Types package for HTTP currency types in the transport and middleware protocols. + +## Overview + +- Proposal: SOAR-0005 +- Author(s): [Honza Dvorsky](https://github.com/czechboy0) +- Status: **Awaiting Review** +- Issue: [apple/swift-openapi-generator#101](https://github.com/apple/swift-openapi-generator/issues/101) +- Implementation: + - [apple/swift-openapi-generator#245](https://github.com/apple/swift-openapi-generator/pull/245) + - [apple/swift-openapi-runtime#47](https://github.com/apple/swift-openapi-runtime/pull/47) + - [apple/swift-openapi-urlsession#15](https://github.com/apple/swift-openapi-urlsession/pull/15) + - [swift-server/swift-openapi-async-http-client#16](https://github.com/swift-server/swift-openapi-async-http-client/pull/16) +- Feature flag: none, lands as a breaking change to main, gets released as 0.3.0 +- Affected components: + - generator + - runtime + - client transports + - server transports + +### Introduction + +Use the HTTP request and response types from the [Swift HTTP Types](https://github.com/apple/swift-http-types) package instead of maintaining our own currency types. + +### Motivation + +The purpose of the Swift OpenAPI Runtime library is to be an "API package", in the meaning established by earlier packages in the Swift ecosystem, such as swift-log. The API package contains generally useful abstractions, which adopters can implement their logic against, and plug in any concrete implementation provided by anyone else in the ecosystem. + +Similarly in Swift OpenAPI Generator, the most important abstractions in the runtime library are the transport and middleware protocols. There are concrete implementations of client and server protocols maintained as separate packages, and an adopter can use any of those concrete implementations with the adopter's generated code. No need to regenerate any code when switching between different transport implementations. + +```swift +// Instantiate a concrete transport implementation. +let transport: any ClientTransport = ... // any client transport + +// Instantiate the generated client by providing it with the transport. +let client = Client(transport: transport) + +// Make API calls +let response = try await client.getStats(...) +... +``` + +The definitions of the transport and middleware protocols currently use currency types provided by the runtime library, representing the HTTP request and response. + +These types need to be maintained and them being specific to the runtime library makes _implementing_ a transport or middleware a little more work, as you need to write code that converts, for example, from `OpenAPIRuntime.Request` to `Foundation.URLRequest`. + +A new package open sourced earlier in 2023 called [Swift HTTP Types](https://github.com/apple/swift-http-types) opens the door to unifying the HTTP request and response types across the Swift ecosystem. By adopting it, we can get following benefits: + +1. No need to maintain `OpenAPIRuntime.Request`, `OpenAPIRuntime.Response`, and friends. +2. Get improvements to Swift HTTP Types for free. +3. Simplify implementing concrete transports and middlewares for libraries that also use Swift HTTP Types (as no manual conversion needed). + +### Proposed solution + +We propose to use the `HTTPRequest` and `HTTPResponse` types (and other types they refer to, such as `HTTPFields`) provided by Swift HTTP Types in the transport and middleware protocols, and delete the request, response, and related types from the runtime library. + +> Note: The Swift HTTP Types library does _not_ contain a currency type that represents HTTP bodies, so we are pitching a new one as part of SOAR-0004 called `OpenAPIRuntime.HTTPBody`. These two proposals are related and below we assume the `HTTPBody` type is available to use. + +### Detailed design + +Let's compare each of the transport and middleware protocols as they are today to what they can be with Swift HTTP Types. Note that in the code snippets below, details not relevant to the proposal, such as code comments, are omitted. + +> Tip: Check out the [source code](https://github.com/apple/swift-http-types) of Swift HTTP Types for more details on the functionality provided by the `HTTPRequest` and `HTTPResponse` types. + +#### Client transport + +The existing `ClientTransport` protocol: + +```swift +public protocol ClientTransport { + func send( + _ request: Request, + baseURL: URL, + operationID: String + ) async throws -> Response +} +``` + +The proposed `ClientTransport` protocol: + +```swift +public protocol ClientTransport { + func send( + _ request: HTTPRequest, // <<< changed + body: HTTPBody?, // <<< added + baseURL: URL, + operationID: String + ) async throws -> (HTTPResponse, HTTPBody) // <<< changed +} +``` + +Notable changes: +- The request and response bodies are passed separately from the request and response metadata types. +- The fully qualified type names used are: + - `HTTPTypes.HTTPRequest` + - `HTTPTypes.HTTPResponse` + - `OpenAPIRuntime.HTTPBody` + +#### Client middleware + +The existing `ClientMiddleware` protocol: + +```swift +public protocol ClientMiddleware: Sendable { + func intercept( + _ request: Request, + baseURL: URL, + operationID: String, + next: @Sendable (Request, URL) async throws -> Response + ) async throws -> Response +} +``` + +The proposed `ClientMiddleware` protocol: + +```swift +public protocol ClientMiddleware { + func intercept( + _ request: HTTPRequest, // <<< changed + body: HTTPBody?, // <<< added + baseURL: URL, + operationID: String, + next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody) // <<< changed + ) async throws -> (HTTPResponse, HTTPBody) // <<< changed +} +``` + +The changes are of the same nature as those to the client transport. + +#### Server transport + +The existing `ServerTransport` protocol: + +```swift +public protocol ServerTransport { + func register( + _ handler: @Sendable @escaping (Request, ServerRequestMetadata) async throws -> Response, + method: HTTPMethod, + path: [RouterPathComponent], + queryItemNames: Set + ) throws +} +``` + +The proposed `ServerTransport` protocol: + +```swift +public protocol ServerTransport { + func register( + _ handler: @Sendable @escaping (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody), // <<< changed + method: HTTPRequest.Method, // <<< changed + path: String // <<< changed + ) throws +} +``` + +Notable changes: +- The `OpenAPIRuntime.ServerRequestMetadata` type removes its `queryParameters` property, as it's not needed as of version 0.2.0, where the query string is decoded directly, instead of receiving the key-value pairs from the transport. We held off the breaking change until 0.3.0, as 0.2.0 did not make breaking changes to the transport and middleware protocols. +- The `path` parameter is now a string instead of an array of parsed components. The string is the templated URI, for example `/pets/{petId}`. This change was made to support [#199](https://github.com/apple/swift-openapi-generator/issues/199) path components that are parameters but also have a constant component, and it is up to the server transport implementation to parse the string and pull parameter names from it. +- Just like client transport, the request and response bodies are passed separately from the request and response metadata types. +- The fully qualified type names used are: + - `HTTPTypes.HTTPRequest` + - `HTTPTypes.HTTPResponse` + - `OpenAPIRuntime.HTTPBody` + +#### Server middleware + +The existing `ServerMiddleware` protocol: + +```swift +public protocol ServerMiddleware: Sendable { + func intercept( + _ request: Request, + metadata: ServerRequestMetadata, + operationID: String, + next: @Sendable (Request, ServerRequestMetadata) async throws -> Response + ) async throws -> Response +} + +``` + +The proposed `ServerMiddleware` protocol: + +```swift +public protocol ServerMiddleware { + func intercept( + _ request: HTTPRequest, // <<< changed + body: HTTPBody?, // <<< added + metadata: ServerRequestMetadata, + operationID: String, + next: @Sendable (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody) // <<< changed + ) async throws -> (HTTPResponse, HTTPBody) // <<< changed +} +``` + +The changes are of the same nature as those to client transport, client middleware, and server transport. + + +### API stability + +The users of concrete transport and middleware implementations will not have to make any changes, only the _implementors_ of transports and middlewares will need to adapt their packages to work with the new currency types. + +### Future directions + +Nothing beyond the same point about the async writer pattern from SOAR-0004. + +### Alternatives considered + +#### Not adopting the package + +An alternative here is to do nothing and not adopt the new package, however since the common HTTP types work so similarly to the types we had to maintain, it was never seriously considered not to take advantage of the common types. While the package is new right now, we expect wider adoption throughout the ecosystem in the coming years, at which point having our own currency types for HTTP requests and responses might be the exception rather than the rule. From 1bf6a8c5d64ff8afc1493d9f57b27fc72d6cc44d Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Fri, 8 Sep 2023 15:04:44 +0200 Subject: [PATCH 2/6] Add links to SOAR-0004 --- .../Documentation.docc/Proposals/SOAR-0005.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md index 4aed5d8f..26ba918d 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -56,7 +56,7 @@ A new package open sourced earlier in 2023 called [Swift HTTP Types](https://git We propose to use the `HTTPRequest` and `HTTPResponse` types (and other types they refer to, such as `HTTPFields`) provided by Swift HTTP Types in the transport and middleware protocols, and delete the request, response, and related types from the runtime library. -> Note: The Swift HTTP Types library does _not_ contain a currency type that represents HTTP bodies, so we are pitching a new one as part of SOAR-0004 called `OpenAPIRuntime.HTTPBody`. These two proposals are related and below we assume the `HTTPBody` type is available to use. +> Note: The Swift HTTP Types library does _not_ contain a currency type that represents HTTP bodies, so we are pitching a new one as part of [SOAR-0004](https://github.com/czechboy0/swift-openapi-generator/blob/hd-soar-0004/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0004.md) called `OpenAPIRuntime.HTTPBody`. These two proposals are related and below we assume the `HTTPBody` type is available to use. ### Detailed design @@ -204,7 +204,7 @@ The users of concrete transport and middleware implementations will not have to ### Future directions -Nothing beyond the same point about the async writer pattern from SOAR-0004. +Nothing beyond the same point about the async writer pattern from [SOAR-0004](https://github.com/czechboy0/swift-openapi-generator/blob/hd-soar-0004/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0004.md). ### Alternatives considered From 74368101c37c4fd8a1d2681f6c9f881b857290df Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Fri, 8 Sep 2023 16:38:12 +0200 Subject: [PATCH 3/6] Feedback: v1.1 --- .../Documentation.docc/Proposals/SOAR-0005.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md index 26ba918d..461f6a6f 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -19,6 +19,9 @@ Adopt the new ecosystem-wide Swift HTTP Types package for HTTP currency types in - runtime - client transports - server transports +- Versions: + - v1 (2023-09-08): Initial version + - v1.1: In `ServerTransport` and `ServerMiddleware`, make the response `HTTPBody` optional to preserve the intent of the OpenAPI document author for the transport. ### Introduction @@ -149,7 +152,7 @@ The proposed `ServerTransport` protocol: ```swift public protocol ServerTransport { func register( - _ handler: @Sendable @escaping (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody), // <<< changed + _ handler: @Sendable @escaping (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody?), // <<< changed method: HTTPRequest.Method, // <<< changed path: String // <<< changed ) throws @@ -190,8 +193,8 @@ public protocol ServerMiddleware { body: HTTPBody?, // <<< added metadata: ServerRequestMetadata, operationID: String, - next: @Sendable (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody) // <<< changed - ) async throws -> (HTTPResponse, HTTPBody) // <<< changed + next: @Sendable (HTTPRequest, HTTPBody?, ServerRequestMetadata) async throws -> (HTTPResponse, HTTPBody?) // <<< changed + ) async throws -> (HTTPResponse, HTTPBody?) // <<< changed } ``` From f722d12f142d41b0e12ee2c7f497d98556afed53 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Fri, 8 Sep 2023 16:47:24 +0200 Subject: [PATCH 4/6] Update SOAR-0005.md --- .../Documentation.docc/Proposals/SOAR-0005.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md index 461f6a6f..26fc8730 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -6,7 +6,7 @@ Adopt the new ecosystem-wide Swift HTTP Types package for HTTP currency types in - Proposal: SOAR-0005 - Author(s): [Honza Dvorsky](https://github.com/czechboy0) -- Status: **Awaiting Review** +- Status: **In Review** - Issue: [apple/swift-openapi-generator#101](https://github.com/apple/swift-openapi-generator/issues/101) - Implementation: - [apple/swift-openapi-generator#245](https://github.com/apple/swift-openapi-generator/pull/245) From 51dae70c50ad03435b9b75752e80f1282d39e9b9 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 13 Sep 2023 17:03:49 +0200 Subject: [PATCH 5/6] Review feedback: make response body optional --- .../Documentation.docc/Proposals/SOAR-0005.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md index 26fc8730..bb93fe4b 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -22,6 +22,7 @@ Adopt the new ecosystem-wide Swift HTTP Types package for HTTP currency types in - Versions: - v1 (2023-09-08): Initial version - v1.1: In `ServerTransport` and `ServerMiddleware`, make the response `HTTPBody` optional to preserve the intent of the OpenAPI document author for the transport. + - v1.2 (2023-09-13): Made response bodies optional. ### Introduction @@ -90,7 +91,7 @@ public protocol ClientTransport { body: HTTPBody?, // <<< added baseURL: URL, operationID: String - ) async throws -> (HTTPResponse, HTTPBody) // <<< changed + ) async throws -> (HTTPResponse, HTTPBody?) // <<< changed } ``` @@ -125,8 +126,8 @@ public protocol ClientMiddleware { body: HTTPBody?, // <<< added baseURL: URL, operationID: String, - next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody) // <<< changed - ) async throws -> (HTTPResponse, HTTPBody) // <<< changed + next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) // <<< changed + ) async throws -> (HTTPResponse, HTTPBody?) // <<< changed } ``` From 98c9c0b3dc7cb3a55b7a3adca38bea21e3ec6684 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Fri, 15 Sep 2023 13:20:52 +0200 Subject: [PATCH 6/6] Update SOAR-0005.md --- .../Documentation.docc/Proposals/SOAR-0005.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md index bb93fe4b..234acf1e 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Proposals/SOAR-0005.md @@ -6,7 +6,7 @@ Adopt the new ecosystem-wide Swift HTTP Types package for HTTP currency types in - Proposal: SOAR-0005 - Author(s): [Honza Dvorsky](https://github.com/czechboy0) -- Status: **In Review** +- Status: **Ready for Implementation** - Issue: [apple/swift-openapi-generator#101](https://github.com/apple/swift-openapi-generator/issues/101) - Implementation: - [apple/swift-openapi-generator#245](https://github.com/apple/swift-openapi-generator/pull/245)