From 392233c3a23003619ac891f4bb34536cf2cac5cf Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Thu, 7 Sep 2023 17:51:05 +0200 Subject: [PATCH 01/11] [WIP] [URLSession Transport] Async bodies + swift-http-types adoption --- .../Documentation.docc/Documentation.md | 2 +- .../URLSessionTransport.swift | 78 ++++++++++++------- .../URLSessionTransportTests.swift | 53 +++++++------ 3 files changed, 83 insertions(+), 50 deletions(-) diff --git a/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md b/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md index c1559a3..a29c7fe 100644 --- a/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md +++ b/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md @@ -11,7 +11,7 @@ Use the transport with client code generated by [Swift OpenAPI Generator](https: ### Supported platforms and minimum versions | macOS | Linux | iOS | tvOS | watchOS | | :-: | :-: | :-: | :-: | :-: | -| ✅ 10.15+ | ✅ | ✅ 13+ | ✅ 13+ | ✅ 6+ | +| ✅ 10.15+ | ✅ | ✅ 13+ | ✅ 13+ | ✅ 6+ | ### Usage diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index 1561969..ae7225d 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// import OpenAPIRuntime +import HTTPTypes #if canImport(Darwin) import Foundation #else @@ -90,13 +91,15 @@ public struct URLSessionTransport: ClientTransport { } public func send( - _ request: OpenAPIRuntime.Request, + _ request: HTTPRequest, + body: HTTPBody?, baseURL: URL, operationID: String - ) async throws -> OpenAPIRuntime.Response { - let urlRequest = try URLRequest(request, baseURL: baseURL) + ) async throws -> (HTTPResponse, HTTPBody) { + // TODO: Investigate how to get bidirectional streaming working. + let urlRequest = try await URLRequest(request, body: body, baseURL: baseURL) let (responseBody, urlResponse) = try await invokeSession(urlRequest) - return try OpenAPIRuntime.Response(from: urlResponse, body: responseBody) + return try HTTPResponse.response(from: urlResponse, body: responseBody) } private func invokeSession(_ urlRequest: URLRequest) async throws -> (Data, URLResponse) { @@ -129,7 +132,7 @@ public struct URLSessionTransport: ClientTransport { internal enum URLSessionTransportError: Error { /// Invalid URL composed from base URL and received request. - case invalidRequestURL(request: OpenAPIRuntime.Request, baseURL: URL) + case invalidRequestURL(path: String, method: HTTPRequest.Method, baseURL: URL) /// Returned `URLResponse` could not be converted to `HTTPURLResponse`. case notHTTPResponse(URLResponse) @@ -138,40 +141,63 @@ internal enum URLSessionTransportError: Error { case noResponse(url: URL?) } -extension OpenAPIRuntime.Response { - init(from urlResponse: URLResponse, body: Data) throws { +extension HTTPResponse { + static func response( + from urlResponse: URLResponse, + body: Data + ) throws -> (HTTPResponse, HTTPBody) { guard let httpResponse = urlResponse as? HTTPURLResponse else { throw URLSessionTransportError.notHTTPResponse(urlResponse) } - let headerFields: [HeaderField] = httpResponse - .allHeaderFields - .compactMap { headerName, headerValue in - guard let name = headerName as? String, let value = headerValue as? String else { - return nil - } - return HeaderField(name: name, value: value) + var headerFields = HTTPFields() + for (headerName, headerValue) in httpResponse.allHeaderFields { + guard + let rawName = headerName as? String, + let name = HTTPField.Name(rawName), + let value = headerValue as? String + else { + continue } - self.init(statusCode: httpResponse.statusCode, headerFields: headerFields, body: body) + headerFields[name] = value + } + return ( + HTTPResponse( + status: .init(code: httpResponse.statusCode), + headerFields: headerFields + ), + .init(data: body) + ) } } extension URLRequest { - init(_ request: OpenAPIRuntime.Request, baseURL: URL) throws { + init(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL) async throws { guard var baseUrlComponents = URLComponents(string: baseURL.absoluteString) else { - throw URLSessionTransportError.invalidRequestURL(request: request, baseURL: baseURL) + throw URLSessionTransportError.invalidRequestURL( + path: request.path ?? "", + method: request.method, + baseURL: baseURL + ) } - baseUrlComponents.percentEncodedPath += request.path - baseUrlComponents.percentEncodedQuery = request.query + + let path = String(request.soar_pathOnly) + baseUrlComponents.percentEncodedPath += path + baseUrlComponents.percentEncodedQuery = request.soar_query.map(String.init) guard let url = baseUrlComponents.url else { - throw URLSessionTransportError.invalidRequestURL(request: request, baseURL: baseURL) + throw URLSessionTransportError.invalidRequestURL( + path: path, + method: request.method, + baseURL: baseURL + ) } self.init(url: url) - self.httpMethod = request.method.name + self.httpMethod = request.method.rawValue for header in request.headerFields { - self.addValue(header.value, forHTTPHeaderField: header.name) + self.addValue(header.value, forHTTPHeaderField: header.name.canonicalName) } - if let body = request.body { - self.httpBody = body + if let body { + // TODO: Avoid buffering, stream intead. + self.httpBody = try await body.collectAsData(upTo: .max) } } } @@ -183,9 +209,9 @@ extension URLSessionTransportError: LocalizedError { extension URLSessionTransportError: CustomStringConvertible { public var description: String { switch self { - case let .invalidRequestURL(request: request, baseURL: baseURL): + case let .invalidRequestURL(path: path, method: method, baseURL: baseURL): return - "Invalid request URL from request path: \(request.path), query: \(request.query ?? "") relative to base URL: \(baseURL.absoluteString)" + "Invalid request URL from request path: \(path), method: \(method), relative to base URL: \(baseURL.absoluteString)" case .notHTTPResponse(let response): return "Received a non-HTTP response, of type: \(String(describing: type(of: response)))" case .noResponse(let url): diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index 25411b8..a14203c 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -27,41 +27,46 @@ import Foundation @preconcurrency import class FoundationNetworking.URLSessionConfiguration #endif @testable import OpenAPIURLSession +import HTTPTypes class URLSessionTransportTests: XCTestCase { - func testRequestConversion() throws { - let request = OpenAPIRuntime.Request( - path: "/hello%20world/Maria", - query: "greeting=Howdy", + func testRequestConversion() async throws { + let request = HTTPRequest( + soar_path: "/hello%20world/Maria?greeting=Howdy", method: .post, headerFields: [ - .init(name: "X-Mumble", value: "mumble") - ], - body: Data("👋".utf8) + .init("X-Mumble")!: "mumble" + ] + ) + let body: HTTPBody = "👋" + let urlRequest = try await URLRequest( + request, + body: body, + baseURL: URL(string: "http://example.com/api")! ) - let urlRequest = try URLRequest(request, baseURL: URL(string: "http://example.com/api")!) XCTAssertEqual(urlRequest.url, URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")) XCTAssertEqual(urlRequest.httpMethod, "POST") - XCTAssertEqual(urlRequest.allHTTPHeaderFields, ["X-Mumble": "mumble"]) + XCTAssertEqual(urlRequest.allHTTPHeaderFields, ["x-mumble": "mumble"]) XCTAssertEqual(urlRequest.httpBody, Data("👋".utf8)) } - func testResponseConversion() throws { + func testResponseConversion() async throws { let urlResponse: URLResponse = HTTPURLResponse( - url: URL(string: "http://example.com/api/hello/Maria?greeting=Howdy")!, + url: URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")!, statusCode: 201, httpVersion: "HTTP/1.1", headerFields: ["X-Mumble": "mumble"] )! - let response = try OpenAPIRuntime.Response(from: urlResponse, body: Data("👋".utf8)) - XCTAssertEqual(response.statusCode, 201) - XCTAssertEqual(response.headerFields, [.init(name: "X-Mumble", value: "mumble")]) - XCTAssertEqual(response.body, Data("👋".utf8)) + let (response, responseBody) = try HTTPResponse.response(from: urlResponse, body: Data("👋".utf8)) + XCTAssertEqual(response.status.code, 201) + XCTAssertEqual(response.headerFields, [.init("X-Mumble")!: "mumble"]) + let bufferedResponseBody = try await responseBody.collectAsString(upTo: .max) + XCTAssertEqual(bufferedResponseBody, "👋") } func testSend() async throws { - let endpointURL = URL(string: "http://example.com/api/hello/Maria?greeting=Howdy")! + let endpointURL = URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")! MockURLProtocol.mockHTTPResponses.withValue { map in map[endpointURL] = .success( ( @@ -73,21 +78,23 @@ class URLSessionTransportTests: XCTestCase { let transport: any ClientTransport = URLSessionTransport( configuration: .init(session: MockURLProtocol.mockURLSession) ) - let request = OpenAPIRuntime.Request( - path: "/hello/Maria", - query: "greeting=Howdy", + let request = HTTPRequest( + soar_path: "/hello%20world/Maria?greeting=Howdy", method: .post, headerFields: [ - .init(name: "X-Mumble", value: "mumble") + .init("X-Mumble")!: "mumble" ] ) - let response = try await transport.send( + let requestBody: HTTPBody = "👋" + let (response, responseBody) = try await transport.send( request, + body: requestBody, baseURL: URL(string: "http://example.com/api")!, operationID: "postGreeting" ) - XCTAssertEqual(response.statusCode, 201) - XCTAssertEqual(response.body, Data("👋".utf8)) + XCTAssertEqual(response.status.code, 201) + let bufferedResponseBody = try await responseBody.collectAsString(upTo: .max) + XCTAssertEqual(bufferedResponseBody, "👋") } } From 69072af387d7e2726dc29735a35b1a8dee3e1204 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 12 Sep 2023 22:30:23 +0200 Subject: [PATCH 02/11] Feedback: further cleanup of the HTTPBody API --- Sources/OpenAPIURLSession/URLSessionTransport.swift | 2 +- Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index ae7225d..298e7e8 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -197,7 +197,7 @@ extension URLRequest { } if let body { // TODO: Avoid buffering, stream intead. - self.httpBody = try await body.collectAsData(upTo: .max) + self.httpBody = try await Data(collecting: body, upTo: .max) } } } diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index a14203c..d470049 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -61,7 +61,7 @@ class URLSessionTransportTests: XCTestCase { let (response, responseBody) = try HTTPResponse.response(from: urlResponse, body: Data("👋".utf8)) XCTAssertEqual(response.status.code, 201) XCTAssertEqual(response.headerFields, [.init("X-Mumble")!: "mumble"]) - let bufferedResponseBody = try await responseBody.collectAsString(upTo: .max) + let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) XCTAssertEqual(bufferedResponseBody, "👋") } @@ -93,7 +93,7 @@ class URLSessionTransportTests: XCTestCase { operationID: "postGreeting" ) XCTAssertEqual(response.status.code, 201) - let bufferedResponseBody = try await responseBody.collectAsString(upTo: .max) + let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) XCTAssertEqual(bufferedResponseBody, "👋") } } From d546187fdd0ccd2fc0d3615b0f12ad035dcd827c Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 13 Sep 2023 17:01:50 +0200 Subject: [PATCH 03/11] Review feedback: make response body optional --- .../URLSessionTransport.swift | 24 ++++++++++++++----- .../URLSessionTransportTests.swift | 10 ++++++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index 298e7e8..e111ca3 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -95,11 +95,15 @@ public struct URLSessionTransport: ClientTransport { body: HTTPBody?, baseURL: URL, operationID: String - ) async throws -> (HTTPResponse, HTTPBody) { + ) async throws -> (HTTPResponse, HTTPBody?) { // TODO: Investigate how to get bidirectional streaming working. let urlRequest = try await URLRequest(request, body: body, baseURL: baseURL) let (responseBody, urlResponse) = try await invokeSession(urlRequest) - return try HTTPResponse.response(from: urlResponse, body: responseBody) + return try HTTPResponse.response( + method: request.method, + urlResponse: urlResponse, + data: responseBody + ) } private func invokeSession(_ urlRequest: URLRequest) async throws -> (Data, URLResponse) { @@ -143,9 +147,10 @@ internal enum URLSessionTransportError: Error { extension HTTPResponse { static func response( - from urlResponse: URLResponse, - body: Data - ) throws -> (HTTPResponse, HTTPBody) { + method: HTTPRequest.Method, + urlResponse: URLResponse, + data: Data + ) throws -> (HTTPResponse, HTTPBody?) { guard let httpResponse = urlResponse as? HTTPURLResponse else { throw URLSessionTransportError.notHTTPResponse(urlResponse) } @@ -160,12 +165,19 @@ extension HTTPResponse { } headerFields[name] = value } + let body: HTTPBody? + switch method { + case .head, .connect, .trace: + body = nil + default: + body = .init(data: data) + } return ( HTTPResponse( status: .init(code: httpResponse.statusCode), headerFields: headerFields ), - .init(data: body) + body ) } } diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index d470049..fc32719 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -58,7 +58,12 @@ class URLSessionTransportTests: XCTestCase { httpVersion: "HTTP/1.1", headerFields: ["X-Mumble": "mumble"] )! - let (response, responseBody) = try HTTPResponse.response(from: urlResponse, body: Data("👋".utf8)) + let (response, maybeResponseBody) = try HTTPResponse.response( + method: .get, + urlResponse: urlResponse, + data: Data("👋".utf8) + ) + let responseBody = try XCTUnwrap(maybeResponseBody) XCTAssertEqual(response.status.code, 201) XCTAssertEqual(response.headerFields, [.init("X-Mumble")!: "mumble"]) let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) @@ -86,12 +91,13 @@ class URLSessionTransportTests: XCTestCase { ] ) let requestBody: HTTPBody = "👋" - let (response, responseBody) = try await transport.send( + let (response, maybeResponseBody) = try await transport.send( request, body: requestBody, baseURL: URL(string: "http://example.com/api")!, operationID: "postGreeting" ) + let responseBody = try XCTUnwrap(maybeResponseBody) XCTAssertEqual(response.status.code, 201) let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) XCTAssertEqual(bufferedResponseBody, "👋") From 74a32a0c557e69dd1ddff511c41e9091751f39e9 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Mon, 25 Sep 2023 14:59:57 +0200 Subject: [PATCH 04/11] Adapted to runtime changes --- Sources/OpenAPIURLSession/URLSessionTransport.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index e111ca3..5fe13d7 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -170,7 +170,7 @@ extension HTTPResponse { case .head, .connect, .trace: body = nil default: - body = .init(data: data) + body = .init(data) } return ( HTTPResponse( From e35ad32d402079e111fce4ea8213075563f56b94 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Tue, 26 Sep 2023 17:30:11 +0200 Subject: [PATCH 05/11] Stop using the generated SPI --- Sources/OpenAPIURLSession/URLSessionTransport.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index 5fe13d7..543b787 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -184,7 +184,10 @@ extension HTTPResponse { extension URLRequest { init(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL) async throws { - guard var baseUrlComponents = URLComponents(string: baseURL.absoluteString) else { + guard + var baseUrlComponents = URLComponents(string: baseURL.absoluteString), + let requestUrlComponents = URLComponents(string: request.path ?? "") + else { throw URLSessionTransportError.invalidRequestURL( path: request.path ?? "", method: request.method, @@ -192,9 +195,9 @@ extension URLRequest { ) } - let path = String(request.soar_pathOnly) + let path = requestUrlComponents.percentEncodedPath baseUrlComponents.percentEncodedPath += path - baseUrlComponents.percentEncodedQuery = request.soar_query.map(String.init) + baseUrlComponents.percentEncodedQuery = requestUrlComponents.percentEncodedQuery guard let url = baseUrlComponents.url else { throw URLSessionTransportError.invalidRequestURL( path: path, From b3a60358fd99fb21f4b8d2119e3e51c23cbbf948 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 08:39:30 +0200 Subject: [PATCH 06/11] Adapt to removed utils in runtime --- .../OpenAPIURLSessionTests/URLSessionTransportTests.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index fc32719..ba8cfaf 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -33,8 +33,10 @@ class URLSessionTransportTests: XCTestCase { func testRequestConversion() async throws { let request = HTTPRequest( - soar_path: "/hello%20world/Maria?greeting=Howdy", method: .post, + scheme: nil, + authority: nil, + path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ .init("X-Mumble")!: "mumble" ] @@ -84,8 +86,10 @@ class URLSessionTransportTests: XCTestCase { configuration: .init(session: MockURLProtocol.mockURLSession) ) let request = HTTPRequest( - soar_path: "/hello%20world/Maria?greeting=Howdy", method: .post, + scheme: nil, + authority: nil, + path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ .init("X-Mumble")!: "mumble" ] From 0edbf40bc60797a95fe332224e13274e37e51516 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 10:27:07 +0200 Subject: [PATCH 07/11] Bump runtime version --- Package.swift | 2 +- Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 1222c48..f1816f0 100644 --- a/Package.swift +++ b/Package.swift @@ -38,7 +38,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-openapi-runtime", "0.1.3" ..< "0.3.0"), + .package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.3.0")), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), ], targets: [ diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index ba8cfaf..d6ccb6c 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -34,7 +34,7 @@ class URLSessionTransportTests: XCTestCase { func testRequestConversion() async throws { let request = HTTPRequest( method: .post, - scheme: nil, + scheme: nil, authority: nil, path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ From 2c2a4dc8323348e073cd467c4882233bb71c89b5 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 10:29:51 +0200 Subject: [PATCH 08/11] Bump versions to 0.3.0 --- README.md | 2 +- Sources/OpenAPIURLSession/Documentation.docc/Documentation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b297385..7f46fae 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add the package dependency in your `Package.swift`: ```swift .package( url: "https://github.com/apple/swift-openapi-urlsession", - .upToNextMinor(from: "0.2.0") + .upToNextMinor(from: "0.3.0") ), ``` diff --git a/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md b/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md index a29c7fe..551611b 100644 --- a/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md +++ b/Sources/OpenAPIURLSession/Documentation.docc/Documentation.md @@ -20,7 +20,7 @@ Add the package dependency in your `Package.swift`: ```swift .package( url: "https://github.com/apple/swift-openapi-urlsession", - .upToNextMinor(from: "0.2.0") + .upToNextMinor(from: "0.3.0") ), ``` From 693ce2bb3209f8f8fbf2a1fa7fb2b730742a710c Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 10:36:45 +0200 Subject: [PATCH 09/11] Fix unit test on linux --- .../OpenAPIURLSessionTests/URLSessionTransportTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index d6ccb6c..4ab5442 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -38,7 +38,7 @@ class URLSessionTransportTests: XCTestCase { authority: nil, path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ - .init("X-Mumble")!: "mumble" + .init("x-mumble")!: "mumble" ] ) let body: HTTPBody = "👋" @@ -58,7 +58,7 @@ class URLSessionTransportTests: XCTestCase { url: URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")!, statusCode: 201, httpVersion: "HTTP/1.1", - headerFields: ["X-Mumble": "mumble"] + headerFields: ["x-mumble": "mumble"] )! let (response, maybeResponseBody) = try HTTPResponse.response( method: .get, @@ -67,7 +67,7 @@ class URLSessionTransportTests: XCTestCase { ) let responseBody = try XCTUnwrap(maybeResponseBody) XCTAssertEqual(response.status.code, 201) - XCTAssertEqual(response.headerFields, [.init("X-Mumble")!: "mumble"]) + XCTAssertEqual(response.headerFields, [.init("x-mumble")!: "mumble"]) let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) XCTAssertEqual(bufferedResponseBody, "👋") } @@ -91,7 +91,7 @@ class URLSessionTransportTests: XCTestCase { authority: nil, path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ - .init("X-Mumble")!: "mumble" + .init("x-mumble")!: "mumble" ] ) let requestBody: HTTPBody = "👋" From 47af975d5a1db4934e6ef2bb07458dfa1eccd4fb Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 10:51:35 +0200 Subject: [PATCH 10/11] Make tests pass --- Sources/OpenAPIURLSession/URLSessionTransport.swift | 2 +- .../URLSessionTransportTests.swift | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index 543b787..d0f8d00 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -208,7 +208,7 @@ extension URLRequest { self.init(url: url) self.httpMethod = request.method.rawValue for header in request.headerFields { - self.addValue(header.value, forHTTPHeaderField: header.name.canonicalName) + self.setValue(header.value, forHTTPHeaderField: header.name.canonicalName) } if let body { // TODO: Avoid buffering, stream intead. diff --git a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift index 4ab5442..c06f11d 100644 --- a/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift +++ b/Tests/OpenAPIURLSessionTests/URLSessionTransportTests.swift @@ -38,7 +38,7 @@ class URLSessionTransportTests: XCTestCase { authority: nil, path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ - .init("x-mumble")!: "mumble" + .init("x-mumble2")!: "mumble" ] ) let body: HTTPBody = "👋" @@ -49,7 +49,8 @@ class URLSessionTransportTests: XCTestCase { ) XCTAssertEqual(urlRequest.url, URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")) XCTAssertEqual(urlRequest.httpMethod, "POST") - XCTAssertEqual(urlRequest.allHTTPHeaderFields, ["x-mumble": "mumble"]) + XCTAssertEqual(urlRequest.allHTTPHeaderFields?.count, 1) + XCTAssertEqual(urlRequest.value(forHTTPHeaderField: "x-mumble2"), "mumble") XCTAssertEqual(urlRequest.httpBody, Data("👋".utf8)) } @@ -58,7 +59,7 @@ class URLSessionTransportTests: XCTestCase { url: URL(string: "http://example.com/api/hello%20world/Maria?greeting=Howdy")!, statusCode: 201, httpVersion: "HTTP/1.1", - headerFields: ["x-mumble": "mumble"] + headerFields: ["x-mumble3": "mumble"] )! let (response, maybeResponseBody) = try HTTPResponse.response( method: .get, @@ -67,7 +68,7 @@ class URLSessionTransportTests: XCTestCase { ) let responseBody = try XCTUnwrap(maybeResponseBody) XCTAssertEqual(response.status.code, 201) - XCTAssertEqual(response.headerFields, [.init("x-mumble")!: "mumble"]) + XCTAssertEqual(response.headerFields, [.init("x-mumble3")!: "mumble"]) let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max) XCTAssertEqual(bufferedResponseBody, "👋") } @@ -91,7 +92,7 @@ class URLSessionTransportTests: XCTestCase { authority: nil, path: "/hello%20world/Maria?greeting=Howdy", headerFields: [ - .init("x-mumble")!: "mumble" + .init("x-mumble1")!: "mumble" ] ) let requestBody: HTTPBody = "👋" From 5fbb0a01ad403122bb5b8ecde8f7deea838e3730 Mon Sep 17 00:00:00 2001 From: Honza Dvorsky Date: Wed, 27 Sep 2023 10:59:16 +0200 Subject: [PATCH 11/11] Reference the issue tracking streaming support --- Sources/OpenAPIURLSession/URLSessionTransport.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/OpenAPIURLSession/URLSessionTransport.swift b/Sources/OpenAPIURLSession/URLSessionTransport.swift index d0f8d00..abadad7 100644 --- a/Sources/OpenAPIURLSession/URLSessionTransport.swift +++ b/Sources/OpenAPIURLSession/URLSessionTransport.swift @@ -96,7 +96,7 @@ public struct URLSessionTransport: ClientTransport { baseURL: URL, operationID: String ) async throws -> (HTTPResponse, HTTPBody?) { - // TODO: Investigate how to get bidirectional streaming working. + // TODO: https://github.com/apple/swift-openapi-generator/issues/301 let urlRequest = try await URLRequest(request, body: body, baseURL: baseURL) let (responseBody, urlResponse) = try await invokeSession(urlRequest) return try HTTPResponse.response( @@ -211,7 +211,7 @@ extension URLRequest { self.setValue(header.value, forHTTPHeaderField: header.name.canonicalName) } if let body { - // TODO: Avoid buffering, stream intead. + // TODO: https://github.com/apple/swift-openapi-generator/issues/301 self.httpBody = try await Data(collecting: body, upTo: .max) } }