Skip to content

Commit

Permalink
Refine HTTPClient and HTTPRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
Alkenso committed Jul 2, 2024
1 parent 9d1610d commit d39b071
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 28 deletions.
36 changes: 32 additions & 4 deletions Sources/SpellbookHTTP/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ open class HTTPClient {

extension HTTPClient {
public func data(for request: HTTPRequest, completion: @escaping (Result<HTTPResult<Data>, Error>) -> Void) {
data(for: try request.urlRequest(), completion: completion)
}

public func data(for request: @autoclosure () throws -> URLRequest, completion: @escaping (Result<HTTPResult<Data>, Error>) -> Void) {
let urlRequest: URLRequest
do {
urlRequest = try request.urlRequest()
urlRequest = try request()
} catch {
completion(.failure(error))
return
Expand All @@ -56,11 +60,21 @@ extension HTTPClient {
}

public func object<T>(
_ type: T.Type = T.self,
for request: HTTPRequest,
decoder: ObjectDecoder<T>,
completion: @escaping (Result<HTTPResult<T>, Error>) -> Void
) {
data(for: request) {
object(type, for: try request.urlRequest(), decoder: decoder, completion: completion)
}

public func object<T>(
_ type: T.Type = T.self,
for request: @autoclosure () throws -> URLRequest,
decoder: ObjectDecoder<T>,
completion: @escaping (Result<HTTPResult<T>, Error>) -> Void
) {
data(for: try request()) {
completion($0.flatMap { dataResult in
Self.decodeResponse(dataResult.value, decoder: decoder)
.map { .init(value: $0, response: dataResult.response) }
Expand All @@ -84,8 +98,14 @@ extension HTTPClient {
for request: HTTPRequest,
delegate: URLSessionTaskDelegate? = nil
) async throws -> HTTPResult<Data> {
let urlRequest = try request.urlRequest()
let (data, response) = try await session.data(for: urlRequest, delegate: delegate)
try await data(for: try request.urlRequest(), delegate: delegate)
}

public func data(
for request: URLRequest,
delegate: URLSessionTaskDelegate? = nil
) async throws -> HTTPResult<Data> {
let (data, response) = try await session.data(for: request, delegate: delegate)
guard let response = response as? HTTPURLResponse else {
throw URLError.badResponseType(response)
}
Expand All @@ -97,6 +117,14 @@ extension HTTPClient {
for request: HTTPRequest,
delegate: URLSessionTaskDelegate? = nil,
decoder: ObjectDecoder<T>
) async throws -> HTTPResult<T> {
try await object(for: try request.urlRequest(), delegate: delegate, decoder: decoder)
}

public func object<T>(
for request: URLRequest,
delegate: URLSessionTaskDelegate? = nil,
decoder: ObjectDecoder<T>
) async throws -> HTTPResult<T> {
let dataResult = try await data(for: request, delegate: delegate)
let object = try Self.decodeResponse(dataResult.value, decoder: decoder).get()
Expand Down
41 changes: 17 additions & 24 deletions Sources/SpellbookHTTP/HTTPRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public struct HTTPRequest {
public var port: UInt16?

public var query: [QueryItem: String] = [:]
public var headers: [Header: HeaderValue] = [:]
public var headers: [Header: String] = [:]
public var body: Body?

public init(urlString: String, method: Method) {
Expand Down Expand Up @@ -68,11 +68,6 @@ extension HTTPRequest {
public var rawValue: String
public init(rawValue: String) { self.rawValue = rawValue }
}

public struct HeaderValue: RawRepresentable, Hashable {
public var rawValue: String
public init(rawValue: String) { self.rawValue = rawValue }
}
}

extension HTTPRequest.Header {
Expand All @@ -83,20 +78,12 @@ extension HTTPRequest.Header: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) { self.rawValue = value }
}

extension HTTPRequest.HeaderValue {
public static func authorization(_ type: HTTPRequest.AuthorizationType, _ token: String) -> Self {
.init(rawValue: "\(type.rawValue) \(token)")
extension HTTPRequest {
public static func authorization(_ type: HTTPRequest.AuthorizationType, _ token: String) -> String {
"\(type.rawValue) \(token)"
}
}

extension HTTPRequest.HeaderValue: ExpressibleByStringLiteral {
public init(stringLiteral value: StringLiteralType) { self.rawValue = value }
}

extension HTTPRequest.HeaderValue: ExpressibleByStringInterpolation {
public init(stringInterpolation: DefaultStringInterpolation) { self.rawValue = stringInterpolation.description }
}

extension HTTPRequest {
public struct AuthorizationType: RawRepresentable, Hashable {
public var rawValue: String
Expand All @@ -114,8 +101,8 @@ extension HTTPRequest.AuthorizationType: ExpressibleByStringInterpolation {

extension HTTPRequest {
public struct Body {
internal let data: () throws -> Data
internal let contentType: String?
public let data: () throws -> Data
public let contentType: String?

public init(contentType: String?, data: @escaping () throws -> Data) {
self.data = data
Expand Down Expand Up @@ -156,7 +143,10 @@ extension HTTPRequest.Body {
extension HTTPRequest {
public func urlRequest() throws -> URLRequest {
guard var components = URLComponents(string: url) else {
fatalError()
throw URLError(.badURL, userInfo: [
NSDebugDescriptionErrorKey: "Failed to parse URLComponents from URL",
SBRelatedObjectErrorKey: url,
])
}
if !query.isEmpty {
components.queryItems = query.map { URLQueryItem(name: $0.key.rawValue, value: $0.value) }
Expand All @@ -165,13 +155,13 @@ extension HTTPRequest {
components.port = Int(port)
}
guard let url = components.url else {
fatalError()
throw URLError(.badURL, userInfo: [
NSDebugDescriptionErrorKey: "Failed to create URL from URLComponents",
SBRelatedObjectErrorKey: url,
])
}

var urlRequest = URLRequest(url: url)
headers.forEach {
urlRequest.setValue($0.value.rawValue, forHTTPHeaderField: $0.key.rawValue)
}
urlRequest.httpMethod = method.rawValue
if let body {
urlRequest.httpBody = try Result { try body.data() }
Expand All @@ -181,6 +171,9 @@ extension HTTPRequest {
urlRequest.addValue(contentType, forHTTPHeaderField: "Content-Type")
}
}
headers.forEach {
urlRequest.setValue($0.value, forHTTPHeaderField: $0.key.rawValue)
}

return urlRequest
}
Expand Down

0 comments on commit d39b071

Please sign in to comment.