Skip to content
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

Minor refactor error handling in async/await extension #45

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
108 changes: 57 additions & 51 deletions Sources/ApexyAlamofire/AlamofireClient+Concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,71 +12,77 @@ import Foundation
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
extension AlamofireClient: ConcurrencyClient {

func observeResponse(
dataResponse: DataResponse<Data, AFError>,
error: Error?) {
private func observeResponse(
info: (request: URLRequest?, data: Data?, response: URLResponse?),
error: Error) {
self.responseObserver?(
dataResponse.request,
dataResponse.response,
dataResponse.data,
info.request,
info.response as? HTTPURLResponse,
info.data,
error)
}

open func request<T>(_ endpoint: T) async throws -> T.Content where T : Endpoint {

let anyRequest = AnyRequest(create: endpoint.makeRequest)
let request = sessionManager.request(anyRequest)
.validate { request, response, data in
Result(catching: { try endpoint.validate(request, response: response, data: data) })
}

let dataResponse = await request.serializingData().response
let result = APIResult<T.Content>(catching: { () throws -> T.Content in
do {
let data = try dataResponse.result.get()
return try endpoint.content(from: dataResponse.response, with: data)
} catch {
throw error.unwrapAlamofireValidationError()
var info: (request: URLRequest?, data: Data?, response: URLResponse?) = (nil, nil, nil)

do {
let anyRequest = AnyRequest(create: endpoint.makeRequest)
let request = sessionManager.request(anyRequest)
.validate { request, response, data in
Result(catching: { try endpoint.validate(request, response: response, data: data) })
}

info.request = request.request

let dataResponse = await request.serializingData().response

info.data = dataResponse.data
info.response = dataResponse.response

let data = try dataResponse.result.get()
return try endpoint.content(from: dataResponse.response, with: data)
} catch {
Task.detached { [weak self, info] in
self?.observeResponse(info: info, error: error)
}
})

Task.detached { [weak self, dataResponse, result] in
self?.observeResponse(dataResponse: dataResponse, error: result.error)
throw error
}

return try result.get()
}

open func upload<T>(_ endpoint: T) async throws -> T.Content where T : UploadEndpoint {

let urlRequest: URLRequest
let body: UploadEndpointBody
(urlRequest, body) = try endpoint.makeRequest()
var info: (request: URLRequest?, data: Data?, response: URLResponse?) = (nil, nil, nil)

let request: UploadRequest
switch body {
case .data(let data):
request = sessionManager.upload(data, with: urlRequest)
case .file(let url):
request = sessionManager.upload(url, with: urlRequest)
case .stream(let stream):
request = sessionManager.upload(stream, with: urlRequest)
}

let dataResponse = await request.serializingData().response
let result = APIResult<T.Content>(catching: { () throws -> T.Content in
do {
let data = try dataResponse.result.get()
return try endpoint.content(from: dataResponse.response, with: data)
} catch {
throw error.unwrapAlamofireValidationError()
do {
let urlRequest: URLRequest
let body: UploadEndpointBody
(urlRequest, body) = try endpoint.makeRequest()

let request: UploadRequest
switch body {
case .data(let data):
request = sessionManager.upload(data, with: urlRequest)
case .file(let url):
request = sessionManager.upload(url, with: urlRequest)
case .stream(let stream):
request = sessionManager.upload(stream, with: urlRequest)
}
})

Task.detached { [weak self, dataResponse, result] in
self?.observeResponse(dataResponse: dataResponse, error: result.error)

info.request = request.request

let dataResponse = await request.serializingData().response

info.data = dataResponse.data
info.response = dataResponse.response

let data = try dataResponse.result.get()
return try endpoint.content(from: dataResponse.response, with: data)
} catch {
Task.detached { [weak self, info] in
self?.observeResponse(info: info, error: error)
}
throw error
}

return try result.get()
}
}
93 changes: 43 additions & 50 deletions Sources/ApexyURLSession/URLSessionClient+Concurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,80 +11,73 @@ import Foundation
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
extension URLSessionClient: ConcurrencyClient {

func observeResponse(
request: URLRequest?,
responseResult: Result<(data: Data, response: URLResponse), Error>) {
let tuple = try? responseResult.get()
private func observeResponse(
info: (request: URLRequest?, data: Data?, response: URLResponse?),
error: Error) {
self.responseObserver?(
request,
tuple?.response as? HTTPURLResponse,
tuple?.data,
responseResult.error)
info.request,
info.response as? HTTPURLResponse,
info.data,
error)
}

open func request<T>(_ endpoint: T) async throws -> T.Content where T : Endpoint {

var request = try endpoint.makeRequest()
request = try requestAdapter.adapt(request)
var responseResult: Result<(data: Data, response: URLResponse), Error>
var info: (request: URLRequest?, data: Data?, response: URLResponse?) = (nil, nil, nil)

do {
let response: (data: Data, response: URLResponse) = try await session.data(for: request)
var request = try endpoint.makeRequest()
request = try requestAdapter.adapt(request)

if let httpResponse = response.response as? HTTPURLResponse {
try endpoint.validate(request, response: httpResponse, data: response.data)
info.request = request

let result: (data: Data, response: URLResponse) = try await session.data(for: request)

info.data = result.data
info.response = result.response

if let httpResponse = result.response as? HTTPURLResponse {
try endpoint.validate(request, response: httpResponse, data: result.data)
}

responseResult = .success(response)
} catch let someError {
responseResult = .failure(someError)
}

Task.detached { [weak self, request, responseResult] in
self?.observeResponse(request: request, responseResult: responseResult)
}

return try responseResult.flatMap { tuple in
do {
return .success(try endpoint.content(from: tuple.response, with: tuple.data))
} catch {
return .failure(error)
return try endpoint.content(from: result.response, with: result.data)
} catch {
Task.detached { [weak self, info] in
self?.observeResponse(info: info, error: error)
}
}.get()
throw error
}
}

open func upload<T>(_ endpoint: T) async throws -> T.Content where T : UploadEndpoint {

var request: (request: URLRequest, body: UploadEndpointBody) = try endpoint.makeRequest()
request.request = try requestAdapter.adapt(request.request)
var responseResult: Result<(data: Data, response: URLResponse), Error>
var info: (request: URLRequest?, data: Data?, response: URLResponse?) = (nil, nil, nil)

do {
let response: (data: Data, response: URLResponse)
var request: (request: URLRequest, body: UploadEndpointBody) = try endpoint.makeRequest()
request.request = try requestAdapter.adapt(request.request)

info.request = request.request

let result: (data: Data, response: URLResponse)
switch request {
case (_, .data(let data)):
response = try await session.upload(for: request.request, from: data)
result = try await session.upload(for: request.request, from: data)
case (_, .file(let url)):
response = try await session.upload(for: request.request, fromFile: url)
result = try await session.upload(for: request.request, fromFile: url)
case (_, .stream):
throw URLSessionClientError.uploadStreamUnimplemented
}

responseResult = .success(response)
} catch let someError {
responseResult = .failure(someError)
}

Task.detached { [weak self, request, responseResult] in
self?.observeResponse(request: request.request, responseResult: responseResult)
}

return try responseResult.flatMap { tuple in
do {
return .success(try endpoint.content(from: tuple.response, with: tuple.data))
} catch {
return .failure(error)
info.data = result.data
info.response = result.response

return try endpoint.content(from: result.response, with: result.data)
} catch {
Task.detached { [weak self, info] in
self?.observeResponse(info: info, error: error)
}
}.get()
throw error
}
}
}
Loading