Skip to content

Disable "respectsExistingLineBreaks" in .swift-format for more consistent styling #23

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .swift-format
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"lineLength" : 120,
"maximumBlankLines" : 1,
"prioritizeKeepingFunctionOutputTogether" : false,
"respectsExistingLineBreaks" : true,
"respectsExistingLineBreaks" : false,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : true,
"AlwaysUseLowerCamelCase" : false,
Expand Down
140 changes: 39 additions & 101 deletions Sources/OpenAPIAsyncHTTPClient/AsyncHTTPClientTransport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,7 @@ public struct AsyncHTTPClientTransport: ClientTransport {

// MARK: LocalizedError

var errorDescription: String? {
description
}
var errorDescription: String? { description }
}

/// A set of configuration values used by the transport.
Expand All @@ -130,21 +128,15 @@ public struct AsyncHTTPClientTransport: ClientTransport {
/// - Parameters:
/// - configuration: A set of configuration values used by the transport.
/// - requestSender: The underlying request sender.
internal init(
configuration: Configuration,
requestSender: any HTTPRequestSending
) {
internal init(configuration: Configuration, requestSender: any HTTPRequestSending) {
self.configuration = configuration
self.requestSender = requestSender
}

/// Creates a new transport.
/// - Parameter configuration: A set of configuration values used by the transport.
public init(configuration: Configuration) {
self.init(
configuration: configuration,
requestSender: AsyncHTTPRequestSender()
)
self.init(configuration: configuration, requestSender: AsyncHTTPRequestSender())
}

// MARK: ClientTransport
Expand All @@ -159,40 +151,27 @@ public struct AsyncHTTPClientTransport: ClientTransport {
///
/// - Returns: A tuple containing the HTTP response and an optional HTTP body in the response.
/// - Throws: An error if the request or response handling encounters any issues.
public func send(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL,
operationID: String
) async throws -> (HTTPResponse, HTTPBody?) {
public func send(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL, operationID: String) async throws -> (
HTTPResponse, HTTPBody?
) {
let httpRequest = try Self.convertRequest(request, body: body, baseURL: baseURL)
let httpResponse = try await invokeSession(with: httpRequest)
let response = try await Self.convertResponse(
method: request.method,
httpResponse: httpResponse
)
let response = try await Self.convertResponse(method: request.method, httpResponse: httpResponse)
return response
}

// MARK: Internal

/// Converts the shared Request type into URLRequest.
internal static func convertRequest(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL
) throws -> HTTPClientRequest {
guard
var baseUrlComponents = URLComponents(string: baseURL.absoluteString),
internal static func convertRequest(_ request: HTTPRequest, body: HTTPBody?, baseURL: URL) throws
-> HTTPClientRequest
{
guard var baseUrlComponents = URLComponents(string: baseURL.absoluteString),
let requestUrlComponents = URLComponents(string: request.path ?? "")
else {
throw Error.invalidRequestURL(request: request, baseURL: baseURL)
}
else { throw Error.invalidRequestURL(request: request, baseURL: baseURL) }
baseUrlComponents.percentEncodedPath += requestUrlComponents.percentEncodedPath
baseUrlComponents.percentEncodedQuery = requestUrlComponents.percentEncodedQuery
guard let url = baseUrlComponents.url else {
throw Error.invalidRequestURL(request: request, baseURL: baseURL)
}
guard let url = baseUrlComponents.url else { throw Error.invalidRequestURL(request: request, baseURL: baseURL) }
var clientRequest = HTTPClientRequest(url: url.absoluteString)
clientRequest.method = request.method.asHTTPMethod
for header in request.headerFields {
Expand All @@ -201,114 +180,73 @@ public struct AsyncHTTPClientTransport: ClientTransport {
if let body {
let length: HTTPClientRequest.Body.Length
switch body.length {
case .unknown:
length = .unknown
case .known(let count):
length = .known(count)
case .unknown: length = .unknown
case .known(let count): length = .known(count)
}
clientRequest.body = .stream(
body.map { .init(bytes: $0) },
length: length
)
clientRequest.body = .stream(body.map { .init(bytes: $0) }, length: length)
}
return clientRequest
}

/// Converts the received URLResponse into the shared Response.
internal static func convertResponse(
method: HTTPRequest.Method,
httpResponse: HTTPClientResponse
) async throws -> (HTTPResponse, HTTPBody?) {
internal static func convertResponse(method: HTTPRequest.Method, httpResponse: HTTPClientResponse) async throws -> (
HTTPResponse, HTTPBody?
) {

var headerFields: HTTPFields = [:]
for header in httpResponse.headers {
headerFields[.init(header.name)!] = header.value
}
for header in httpResponse.headers { headerFields[.init(header.name)!] = header.value }

let length: HTTPBody.Length
if let lengthHeaderString = headerFields[.contentLength],
let lengthHeader = Int(lengthHeaderString)
{
if let lengthHeaderString = headerFields[.contentLength], let lengthHeader = Int(lengthHeaderString) {
length = .known(lengthHeader)
} else {
length = .unknown
}

let body: HTTPBody?
switch method {
case .head, .connect, .trace:
body = nil
case .head, .connect, .trace: body = nil
default:
body = HTTPBody(
httpResponse.body.map { $0.readableBytesView },
length: length,
iterationBehavior: .single
)
body = HTTPBody(httpResponse.body.map { $0.readableBytesView }, length: length, iterationBehavior: .single)
}

let response = HTTPResponse(
status: .init(code: Int(httpResponse.status.code)),
headerFields: headerFields
)
let response = HTTPResponse(status: .init(code: Int(httpResponse.status.code)), headerFields: headerFields)
return (response, body)
}

// MARK: Private

/// Makes the underlying HTTP call.
private func invokeSession(with request: Request) async throws -> Response {
try await requestSender.send(
request: request,
with: configuration.client,
timeout: configuration.timeout
)
try await requestSender.send(request: request, with: configuration.client, timeout: configuration.timeout)
}
}

extension HTTPTypes.HTTPRequest.Method {
var asHTTPMethod: NIOHTTP1.HTTPMethod {
switch self {
case .get:
return .GET
case .put:
return .PUT
case .post:
return .POST
case .delete:
return .DELETE
case .options:
return .OPTIONS
case .head:
return .HEAD
case .patch:
return .PATCH
case .trace:
return .TRACE
default:
return .RAW(value: rawValue)
case .get: return .GET
case .put: return .PUT
case .post: return .POST
case .delete: return .DELETE
case .options: return .OPTIONS
case .head: return .HEAD
case .patch: return .PATCH
case .trace: return .TRACE
default: return .RAW(value: rawValue)
}
}
}

/// A type that performs HTTP operations using the HTTP client.
internal protocol HTTPRequestSending: Sendable {
func send(
request: AsyncHTTPClientTransport.Request,
with client: HTTPClient,
timeout: TimeAmount
) async throws -> AsyncHTTPClientTransport.Response
func send(request: AsyncHTTPClientTransport.Request, with client: HTTPClient, timeout: TimeAmount) async throws
-> AsyncHTTPClientTransport.Response
}

/// Performs HTTP calls using AsyncHTTPClient
internal struct AsyncHTTPRequestSender: HTTPRequestSending {
func send(
request: AsyncHTTPClientTransport.Request,
with client: AsyncHTTPClient.HTTPClient,
timeout: TimeAmount
) async throws -> AsyncHTTPClientTransport.Response {
try await client.execute(
request,
timeout: timeout
)
}
func send(request: AsyncHTTPClientTransport.Request, with client: AsyncHTTPClient.HTTPClient, timeout: TimeAmount)
async throws -> AsyncHTTPClientTransport.Response
{ try await client.execute(request, timeout: timeout) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,12 @@ import HTTPTypes

class Test_AsyncHTTPClientTransport: XCTestCase {

static var testData: Data {
get throws {
try XCTUnwrap(#"[{}]"#.data(using: .utf8))
}
}
static var testData: Data { get throws { try XCTUnwrap(#"[{}]"#.data(using: .utf8)) } }

static var testBuffer: ByteBuffer {
ByteBuffer(string: #"[{}]"#)
}
static var testBuffer: ByteBuffer { ByteBuffer(string: #"[{}]"#) }

static var testUrl: URL {
get throws {
try XCTUnwrap(URL(string: "http://example.com/api/v1/hello/Maria?greeting=Howdy"))
}
get throws { try XCTUnwrap(URL(string: "http://example.com/api/v1/hello/Maria?greeting=Howdy")) }
}

func testConvertRequest() throws {
Expand All @@ -43,9 +35,7 @@ class Test_AsyncHTTPClientTransport: XCTestCase {
scheme: nil,
authority: nil,
path: "/hello%20world/Maria?greeting=Howdy",
headerFields: [
.contentType: "application/json"
]
headerFields: [.contentType: "application/json"]
)
let requestBody = try HTTPBody(Self.testData)
let httpRequest = try AsyncHTTPClientTransport.convertRequest(
Expand All @@ -55,22 +45,15 @@ class Test_AsyncHTTPClientTransport: XCTestCase {
)
XCTAssertEqual(httpRequest.url, "http://example.com/api/v1/hello%20world/Maria?greeting=Howdy")
XCTAssertEqual(httpRequest.method, .POST)
XCTAssertEqual(
httpRequest.headers,
[
"content-type": "application/json"
]
)
XCTAssertEqual(httpRequest.headers, ["content-type": "application/json"])
// TODO: Not sure how to test that httpRequest.body is what we expect, can't
// find an API for reading it back.
}

func testConvertResponse() async throws {
let httpResponse = HTTPClientResponse(
status: .ok,
headers: [
"content-type": "application/json"
],
headers: ["content-type": "application/json"],
body: .bytes(Self.testBuffer)
)
let (response, maybeResponseBody) = try await AsyncHTTPClientTransport.convertResponse(
Expand All @@ -79,29 +62,19 @@ class Test_AsyncHTTPClientTransport: XCTestCase {
)
let responseBody = try XCTUnwrap(maybeResponseBody)
XCTAssertEqual(response.status.code, 200)
XCTAssertEqual(
response.headerFields,
[
.contentType: "application/json"
]
)
XCTAssertEqual(response.headerFields, [.contentType: "application/json"])
let bufferedResponseBody = try await Data(collecting: responseBody, upTo: .max)
XCTAssertEqual(bufferedResponseBody, try Self.testData)
}

func testSend() async throws {
let transport = AsyncHTTPClientTransport(
configuration: .init(),
requestSender: TestSender.test
)
let transport = AsyncHTTPClientTransport(configuration: .init(), requestSender: TestSender.test)
let request: HTTPRequest = .init(
method: .get,
scheme: nil,
authority: nil,
path: "/api/v1/hello/Maria",
headerFields: [
.init("x-request")!: "yes"
]
headerFields: [.init("x-request")!: "yes"]
)
let (response, maybeResponseBody) = try await transport.send(
request,
Expand All @@ -120,22 +93,16 @@ struct TestSender: HTTPRequestSending {
var sendClosure:
@Sendable (AsyncHTTPClientTransport.Request, HTTPClient, TimeAmount) async throws ->
AsyncHTTPClientTransport.Response
func send(
request: AsyncHTTPClientTransport.Request,
with client: HTTPClient,
timeout: TimeAmount
) async throws -> AsyncHTTPClientTransport.Response {
try await sendClosure(request, client, timeout)
}
func send(request: AsyncHTTPClientTransport.Request, with client: HTTPClient, timeout: TimeAmount) async throws
-> AsyncHTTPClientTransport.Response
{ try await sendClosure(request, client, timeout) }

static var test: Self {
TestSender { request, _, _ in
XCTAssertEqual(request.headers.first(name: "x-request"), "yes")
return HTTPClientResponse(
status: .ok,
headers: [
"content-type": "application/json"
],
headers: ["content-type": "application/json"],
body: .bytes(Test_AsyncHTTPClientTransport.testBuffer)
)
}
Expand Down