Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0a0c648

Browse files
[AHC Transport] Async bodies + swift-http-types adoption (#16)
[AHC Transport] Async bodies + swift-http-types adoption ### Motivation AHC transport changes of the approved proposals apple/swift-openapi-generator#255 and apple/swift-openapi-generator#254. ### Modifications - Adapts to the runtime changes, depends on HTTPTypes now. - Both request and response streaming works. ### Result Transport works with the 0.3.0 runtime API of. ### Test Plan Adapted tests. Reviewed by: dnadoba, simonjbeaumont Builds: ✔︎ pull request validation (5.8) - Build finished. ✔︎ pull request validation (5.9) - Build finished. ✔︎ pull request validation (nightly) - Build finished. ✔︎ pull request validation (soundness) - Build finished. #16
1 parent f228a33 commit 0a0c648

File tree

5 files changed

+99
-44
lines changed

5 files changed

+99
-44
lines changed

‎Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ let package = Package(
4040
dependencies: [
4141
.package(url: "https://github.com/apple/swift-nio", from: "2.58.0"),
4242
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.19.0"),
43-
.package(url: "https://github.com/apple/swift-openapi-runtime", "0.1.3"..<"0.3.0"),
43+
.package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from:"0.3.0")),
4444
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
4545
],
4646
targets: [

‎README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Add the package dependency in your `Package.swift`:
1616
```swift
1717
.package(
1818
url: "https://github.com/swift-server/swift-openapi-async-http-client",
19-
.upToNextMinor(from: "0.2.0")
19+
.upToNextMinor(from: "0.3.0")
2020
),
2121
```
2222

‎Sources/OpenAPIAsyncHTTPClient/AsyncHTTPClientTransport.swift

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import AsyncHTTPClient
1616
import NIOCore
1717
import NIOHTTP1
1818
import NIOFoundationCompat
19+
import HTTPTypes
1920
#if canImport(Darwin)
2021
import Foundation
2122
#else
@@ -100,15 +101,15 @@ public struct AsyncHTTPClientTransport: ClientTransport {
100101
internal enum Error: Swift.Error, CustomStringConvertible, LocalizedError {
101102

102103
/// Invalid URL composed from base URL and received request.
103-
case invalidRequestURL(request: OpenAPIRuntime.Request, baseURL: URL)
104+
case invalidRequestURL(request: HTTPRequest, baseURL: URL)
104105

105106
// MARK: CustomStringConvertible
106107

107108
var description: String {
108109
switch self {
109110
case let .invalidRequestURL(request: request, baseURL: baseURL):
110111
return
111-
"Invalid request URL from request path: \(request.path), query: \(request.query ?? "<nil>") relative to base URL: \(baseURL.absoluteString)"
112+
"Invalid request URL from request path: \(request.path ?? "<nil>") relative to base URL: \(baseURL.absoluteString)"
112113
}
113114
}
114115

@@ -150,57 +151,97 @@ public struct AsyncHTTPClientTransport: ClientTransport {
150151
// MARK: ClientTransport
151152

152153
public func send(
153-
_ request: OpenAPIRuntime.Request,
154+
_ request: HTTPRequest,
155+
body: HTTPBody?,
154156
baseURL: URL,
155157
operationID: String
156-
) async throws -> OpenAPIRuntime.Response {
157-
let httpRequest = try Self.convertRequest(request, baseURL: baseURL)
158+
) async throws -> (HTTPResponse,HTTPBody?) {
159+
let httpRequest = try Self.convertRequest(request, body: body,baseURL: baseURL)
158160
let httpResponse = try await invokeSession(with: httpRequest)
159-
let response = try await Self.convertResponse(httpResponse)
161+
let response = try await Self.convertResponse(
162+
method: request.method,
163+
httpResponse: httpResponse
164+
)
160165
return response
161166
}
162167

163168
// MARK: Internal
164169

165170
/// Converts the shared Request type into URLRequest.
166171
internal static func convertRequest(
167-
_ request: OpenAPIRuntime.Request,
172+
_ request: HTTPRequest,
173+
body: HTTPBody?,
168174
baseURL: URL
169175
) throws -> HTTPClientRequest {
170-
guard var baseUrlComponents = URLComponents(string: baseURL.absoluteString) else {
176+
guard
177+
var baseUrlComponents = URLComponents(string: baseURL.absoluteString),
178+
let requestUrlComponents = URLComponents(string: request.path ?? "")
179+
else {
171180
throw Error.invalidRequestURL(request: request, baseURL: baseURL)
172181
}
173-
baseUrlComponents.percentEncodedPath += request.path
174-
baseUrlComponents.percentEncodedQuery = request.query
182+
baseUrlComponents.percentEncodedPath += requestUrlComponents.percentEncodedPath
183+
baseUrlComponents.percentEncodedQuery = requestUrlComponents.percentEncodedQuery
175184
guard let url = baseUrlComponents.url else {
176185
throw Error.invalidRequestURL(request: request, baseURL: baseURL)
177186
}
178187
var clientRequest = HTTPClientRequest(url: url.absoluteString)
179188
clientRequest.method = request.method.asHTTPMethod
180189
for header in request.headerFields {
181-
clientRequest.headers.add(name: header.name.lowercased(), value: header.value)
190+
clientRequest.headers.add(name: header.name.canonicalName, value: header.value)
182191
}
183-
if let body = request.body {
184-
clientRequest.body = .bytes(body)
192+
if let body {
193+
let length: HTTPClientRequest.Body.Length
194+
switch body.length {
195+
case .unknown:
196+
length = .unknown
197+
case .known(let count):
198+
length = .known(count)
199+
}
200+
clientRequest.body = .stream(
201+
body.map { .init(bytes: 0ドル) },
202+
length: length
203+
)
185204
}
186205
return clientRequest
187206
}
188207

189208
/// Converts the received URLResponse into the shared Response.
190209
internal static func convertResponse(
191-
_ httpResponse: HTTPClientResponse
192-
) async throws -> OpenAPIRuntime.Response {
193-
let headerFields: [OpenAPIRuntime.HeaderField] = httpResponse
194-
.headers
195-
.map { .init(name: 0ドル, value: 1ドル) }
196-
let body = try await httpResponse.body.collect(upTo: .max)
197-
let bodyData = Data(buffer: body, byteTransferStrategy: .noCopy)
198-
let response = OpenAPIRuntime.Response(
199-
statusCode: Int(httpResponse.status.code),
200-
headerFields: headerFields,
201-
body: bodyData
210+
method: HTTPRequest.Method,
211+
httpResponse: HTTPClientResponse
212+
) async throws -> (HTTPResponse, HTTPBody?) {
213+
214+
var headerFields: HTTPFields = [:]
215+
for header in httpResponse.headers {
216+
headerFields[.init(header.name)!] = header.value
217+
}
218+
219+
let length: HTTPBody.Length
220+
if let lengthHeaderString = headerFields[.contentLength],
221+
let lengthHeader = Int(lengthHeaderString)
222+
{
223+
length = .known(lengthHeader)
224+
} else {
225+
length = .unknown
226+
}
227+
228+
let body: HTTPBody?
229+
switch method {
230+
case .head, .connect, .trace:
231+
body = nil
232+
default:
233+
body = HTTPBody(
234+
httpResponse.body.map { 0ドル.readableBytesView },
235+
length: length,
236+
iterationBehavior: .single
237+
)
238+
}
239+
240+
let response = HTTPResponse(
241+
status: .init(code: Int(httpResponse.status.code)),
242+
headerFields: headerFields
202243
)
203-
return response
244+
return (response, body)
204245
}
205246

206247
// MARK: Private
@@ -215,7 +256,7 @@ public struct AsyncHTTPClientTransport: ClientTransport {
215256
}
216257
}
217258

218-
extension OpenAPIRuntime.HTTPMethod {
259+
extension HTTPTypes.HTTPRequest.Method {
219260
var asHTTPMethod: NIOHTTP1.HTTPMethod {
220261
switch self {
221262
case .get:

‎Sources/OpenAPIAsyncHTTPClient/Documentation.docc/Documentation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Add the package dependency in your `Package.swift`:
2020
```swift
2121
.package(
2222
url: "https://github.com/swift-server/swift-openapi-async-http-client",
23-
.upToNextMinor(from: "0.2.0")
23+
.upToNextMinor(from: "0.3.0")
2424
),
2525
```
2626

‎Tests/OpenAPIAsyncHTTPClientTests/Test_AsyncHTTPClientTransport.swift

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import NIOCore
1717
import NIOPosix
1818
import AsyncHTTPClient
1919
@testable import OpenAPIAsyncHTTPClient
20+
import HTTPTypes
2021

2122
class Test_AsyncHTTPClientTransport: XCTestCase {
2223

@@ -37,17 +38,19 @@ class Test_AsyncHTTPClientTransport: XCTestCase {
3738
}
3839

3940
func testConvertRequest() throws {
40-
let request: OpenAPIRuntime.Request = .init(
41-
path: "/hello%20world/Maria",
42-
query: "greeting=Howdy",
41+
let request: HTTPRequest = .init(
4342
method: .post,
43+
scheme: nil,
44+
authority: nil,
45+
path: "/hello%20world/Maria?greeting=Howdy",
4446
headerFields: [
45-
.init(name: "content-type", value: "application/json")
46-
],
47-
body: try Self.testData
47+
.contentType: "application/json"
48+
]
4849
)
50+
let requestBody = try HTTPBody(Self.testData)
4951
let httpRequest = try AsyncHTTPClientTransport.convertRequest(
5052
request,
53+
body: requestBody,
5154
baseURL: try XCTUnwrap(URL(string: "http://example.com/api/v1"))
5255
)
5356
XCTAssertEqual(httpRequest.url, "http://example.com/api/v1/hello%20world/Maria?greeting=Howdy")
@@ -70,35 +73,46 @@ class Test_AsyncHTTPClientTransport: XCTestCase {
7073
],
7174
body: .bytes(Self.testBuffer)
7275
)
73-
let response = try await AsyncHTTPClientTransport.convertResponse(httpResponse)
74-
XCTAssertEqual(response.statusCode, 200)
76+
let (response, maybeResponseBody) = try await AsyncHTTPClientTransport.convertResponse(
77+
method: .get,
78+
httpResponse: httpResponse
79+
)
80+
let responseBody = try XCTUnwrap(maybeResponseBody)
81+
XCTAssertEqual(response.status.code, 200)
7582
XCTAssertEqual(
7683
response.headerFields,
7784
[
78-
.init(name: "content-type", value:"application/json")
85+
.contentType: "application/json"
7986
]
8087
)
81-
XCTAssertEqual(response.body, try Self.testData)
88+
let bufferedResponseBody = try await Data(collecting: responseBody, upTo: .max)
89+
XCTAssertEqual(bufferedResponseBody, try Self.testData)
8290
}
8391

8492
func testSend() async throws {
8593
let transport = AsyncHTTPClientTransport(
8694
configuration: .init(),
8795
requestSender: TestSender.test
8896
)
89-
let request: OpenAPIRuntime.Request = .init(
90-
path: "/api/v1/hello/Maria",
97+
let request: HTTPRequest = .init(
9198
method: .get,
99+
scheme: nil,
100+
authority: nil,
101+
path: "/api/v1/hello/Maria",
92102
headerFields: [
93-
.init(name:"x-request", value: "yes")
103+
.init("x-request")!: "yes"
94104
]
95105
)
96-
let response = try await transport.send(
106+
let (response, maybeResponseBody) = try await transport.send(
97107
request,
108+
body: nil,
98109
baseURL: Self.testUrl,
99110
operationID: "sayHello"
100111
)
101-
XCTAssertEqual(response.statusCode, 200)
112+
let responseBody = try XCTUnwrap(maybeResponseBody)
113+
let bufferedResponseBody = try await String(collecting: responseBody, upTo: .max)
114+
XCTAssertEqual(bufferedResponseBody, "[{}]")
115+
XCTAssertEqual(response.status.code, 200)
102116
}
103117
}
104118

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /