Skip to content

Commit e1f84a3

Browse files
committed
Resource with generic Error as default
1 parent a0e2245 commit e1f84a3

22 files changed

+87
-103
lines changed

Source/NetworkService+ResourceWithError.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ extension NetworkService {
5252
*/
5353
@discardableResult
5454
public func requestResultWithResponse<Success, E: Error>(
55-
for resource: ResourceWithError<Success, E>
55+
for resource: Resource<Success, E>
5656
) async -> Result<(Success, HTTPURLResponse), E> {
57-
let resourceWithoutError = Resource(request: resource.request, parse: resource.parse)
57+
let resourceWithoutError = Resource<Success, NetworkError>(request: resource.request, parse: resource.parse)
5858
return await self.requestResultWithResponse(for: resourceWithoutError)
5959
.mapError(resource.mapError)
6060
}
@@ -85,9 +85,9 @@ extension NetworkService {
8585
*/
8686
@discardableResult
8787
public func requestResult<Success, E: Error>(
88-
for resource: ResourceWithError<Success, E>
88+
for resource: Resource<Success, E>
8989
) async -> Result<Success, E> {
90-
let resourceWithoutError = Resource(request: resource.request, parse: resource.parse)
90+
let resourceWithoutError = Resource<Success, NetworkError>(request: resource.request, parse: resource.parse)
9191
return await requestResultWithResponse(for: resourceWithoutError)
9292
.mapError(resource.mapError)
9393
.map({ $0.0 })
@@ -120,13 +120,18 @@ extension NetworkService {
120120
*/
121121
@discardableResult
122122
public func request<Success, E: Error>(
123-
_ resource: ResourceWithError<Success, E>
123+
_ resource: Resource<Success, E>
124124
) async throws -> Success {
125-
let resourceWithoutError = Resource(request: resource.request, parse: resource.parse)
125+
let resourceWithoutError = Resource<Success, NetworkError>(request: resource.request, parse: resource.parse)
126126
return try await requestResultWithResponse(for: resourceWithoutError)
127127
.mapError(resource.mapError)
128128
.map({ $0.0 })
129129
.get()
130130
}
131131

132+
@discardableResult
133+
func requestWithResponse<Success, E: Error>(for resource: Resource<Success, E>) async throws -> (Success, HTTPURLResponse) {
134+
return try await requestResultWithResponse(for: resource).get()
135+
}
136+
132137
}

Source/NetworkService.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public protocol NetworkService: Sendable {
5757
- returns: a running network task
5858
*/
5959
@discardableResult
60-
func requestResultWithResponse<Success>(for resource: Resource<Success>) async -> Result<(Success, HTTPURLResponse), NetworkError>
60+
func requestResultWithResponse<Success>(for resource: Resource<Success, NetworkError>) async -> Result<(Success, HTTPURLResponse), NetworkError>
6161
}
6262

6363
public extension NetworkService {
@@ -87,7 +87,7 @@ public extension NetworkService {
8787
- returns: a running network task
8888
*/
8989
@discardableResult
90-
func requestResult<Success>(for resource: Resource<Success>) async -> Result<Success, NetworkError> {
90+
func requestResult<Success>(for resource: Resource<Success, NetworkError>) async -> Result<Success, NetworkError> {
9191
return await requestResultWithResponse(for: resource).map({ $0.0 })
9292
}
9393

@@ -116,7 +116,12 @@ public extension NetworkService {
116116
- returns: a running network task
117117
*/
118118
@discardableResult
119-
func request<Success>(_ resource: Resource<Success>) async throws -> Success {
119+
func request<Success>(_ resource: Resource<Success, NetworkError>) async throws -> Success {
120120
return try await requestResultWithResponse(for: resource).get().0
121121
}
122+
123+
@discardableResult
124+
func requestWithResponse<Success>(for resource: Resource<Success, NetworkError>) async throws -> (Success, HTTPURLResponse) {
125+
return try await requestResultWithResponse(for: resource).get()
126+
}
122127
}

Source/NetworkServices/BasicNetworkService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public final class BasicNetworkService: NetworkService {
7373
- returns: a running network task
7474
*/
7575
@discardableResult
76-
public func requestResultWithResponse<Success>(for resource: Resource<Success>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
76+
public func requestResultWithResponse<Success>(for resource: Resource<Success, NetworkError>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
7777
do {
7878
let (data, response) = try await networkAccess.load(request: resource.request)
7979
guard let response = response as? HTTPURLResponse else {

Source/NetworkServices/ModifyRequestNetworkService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ public final class ModifyRequestNetworkService: NetworkService {
8080
- returns: a running network task
8181
*/
8282
@discardableResult
83-
public func requestResultWithResponse<Success>(for resource: Resource<Success>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
83+
public func requestResultWithResponse<Success>(for resource: Resource<Success, NetworkError>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
8484
let request = requestModifications.reduce(resource.request, { request, modify in
8585
return modify(request)
8686
})
87-
let newResource = Resource(request: request, parse: resource.parse)
87+
let newResource = Resource<Success, NetworkError>(request: request, parse: resource.parse)
8888
return await networkService.requestResultWithResponse(for: newResource)
8989
}
9090
}

Source/NetworkServices/NetworkServiceMock.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public final actor NetworkServiceMock: NetworkService {
147147
- parameter onError: Callback which gets called when fetching or transforming fails.
148148

149149
*/
150-
public func requestResultWithResponse<Success>(for resource: Resource<Success>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
150+
public func requestResultWithResponse<Success>(for resource: Resource<Success, NetworkError>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
151151
lastRequests.append(resource.request)
152152
if !responses.isEmpty {
153153
let scheduled = responses.removeFirst()

Source/NetworkServices/RetryNetworkService.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public final class RetryNetworkService: NetworkService {
8181

8282
- returns: a running network task
8383
*/
84-
public func requestResultWithResponse<Success>(for resource: Resource<Success>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
84+
public func requestResultWithResponse<Success>(for resource: Resource<Success, NetworkError>) async -> Result<(Success, HTTPURLResponse), NetworkError> {
8585
let result = await networkService.requestResultWithResponse(for: resource)
8686
switch result {
8787
case .success:
@@ -94,20 +94,24 @@ public final class RetryNetworkService: NetworkService {
9494
private func requestResultWithResponseOnError<Success>(
9595
error: NetworkError,
9696
numberOfRetriesLeft: Int,
97-
resource: Resource<Success>
97+
resource: Resource<Success, NetworkError>
9898
) async -> Result<(Success, HTTPURLResponse), NetworkError> {
9999
if self.shouldRetry(error), numberOfRetriesLeft > 0 {
100100
let duration = UInt64(idleTimeInterval * 1_000_000_000)
101101
try? await Task.sleep(nanoseconds: duration)
102-
#warning("check for cancellation")
103-
104-
let result = await networkService.requestResultWithResponse(for: resource)
105-
switch result {
106-
case .success:
107-
return result
108-
case .failure(let failure):
109-
return await requestResultWithResponseOnError(error: failure, numberOfRetriesLeft: numberOfRetriesLeft - 1, resource: resource)
102+
do {
103+
try Task.checkCancellation()
104+
let result = await networkService.requestResultWithResponse(for: resource)
105+
switch result {
106+
case .success:
107+
return result
108+
case .failure(let failure):
109+
return await requestResultWithResponseOnError(error: failure, numberOfRetriesLeft: numberOfRetriesLeft - 1, resource: resource)
110+
}
111+
} catch {
112+
return .failure(.cancelled)
110113
}
114+
111115
} else {
112116
return .failure(error)
113117
}

Source/Resource+Decodable.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ extension Resource where Model: Decodable {
3131
/// - Parameters:
3232
/// - request: The request to get the remote data payload
3333
/// - decoder: a decoder which can decode the payload into the model type
34-
public init(request: URLRequest, decoder: JSONDecoder) {
35-
self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) })
34+
/// - mapError: a closure which maps to Error
35+
public init(request: URLRequest, decoder: JSONDecoder, mapError: @escaping (_ networkError: NetworkError) -> E) {
36+
self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) }, mapError: mapError)
3637
}
3738
}
3839

39-
extension ResourceWithError where Model: Decodable {
40+
extension Resource where Model: Decodable, E: NetworkErrorConvertible {
4041

4142
/// Creates an instace of Resource where the result type is `Decodable` and
4243
/// can be decoded with the given decoder
@@ -45,7 +46,7 @@ extension ResourceWithError where Model: Decodable {
4546
/// - request: The request to get the remote data payload
4647
/// - decoder: a decoder which can decode the payload into the model type
4748
/// - mapError: a closure which maps to Error
48-
public init(request: URLRequest, decoder: JSONDecoder, mapError: @escaping (_ networkError: NetworkError) -> E) {
49-
self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) }, mapError: mapError)
49+
public init(request: URLRequest, decoder: JSONDecoder) {
50+
self.init(request: request, parse: { try decoder.decode(Model.self, from: $0) }, mapError: { E(networkError: $0) })
5051
}
5152
}

Source/Resource+Inspect.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extension Resource {
2727
This lets one inspect the data payload before data gets parsed.
2828

2929
```swift
30-
let resource: Resource<Train> = //
30+
let resource: Resource<Train, NetworkError> = //
3131
resource.inspectData { data in
3232
print(String(bytes: data, encoding: .utf8))
3333
}
@@ -36,11 +36,12 @@ extension Resource {
3636
- parameter inspector: closure which gets passed the data
3737
- returns: a new resource which gets instepcted before parsing
3838
*/
39-
public func inspectData(_ inspector: @escaping (Data) -> Void) -> Resource<Model> {
40-
return Resource(request: request, parse: { data in
39+
public func inspectData(_ inspector: @escaping (Data) -> Void) -> Resource<Model, E> {
40+
let parse: (Data) throws -> Model = { data in
4141
inspector(data)
4242
return try self.parse(data)
43-
})
43+
}
44+
return Resource<Model, E>(request: request, parse: parse, mapError: mapError)
4445
}
4546

4647
}

Source/Resource+Map.swift

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,10 @@ extension Resource {
2727
///
2828
/// - Parameter transform: transforms the original result of the resource
2929
/// - Returns: the transformed resource
30-
public func map<T>(transform: @escaping (Model) throws -> T) -> Resource<T> {
31-
return Resource<T>(request: request, parse: { data in
32-
return try transform(try self.parse(data))
33-
})
34-
}
35-
}
36-
37-
extension ResourceWithError {
38-
39-
/// Maps a resource result to a different resource. This is useful when you have result of R which contains T and your API request a resource of T,
40-
///
41-
/// Error parsing is not changed
42-
///
43-
/// - Parameter transform: transforms the original result of the resource
44-
/// - Returns: the transformed resource
45-
public func map<T>(transform: @escaping (Model) throws -> T) -> ResourceWithError<T, E> {
46-
return ResourceWithError<T, E>(
30+
public func map<T>(transform: @escaping (Model) throws -> T) -> Resource<T, E> {
31+
return Resource<T, E>(
4732
request: request,
48-
parse: { data in
49-
return try transform(try self.parse(data))
50-
},
33+
parse: { return try transform(try self.parse($0)) },
5134
mapError: mapError
5235
)
5336
}

Source/Resource+Void.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,20 @@ public extension Resource where Model == Void {
1313
///
1414
/// - Parameters:
1515
/// - request: The request to get the remote data payload
16-
init(request: URLRequest) {
17-
self.init(request: request, parse: { _ in })
16+
/// - mapError: a closure which maps to Error
17+
init(request: URLRequest, mapError: @escaping (_ networkError: NetworkError) -> E) {
18+
self.init(request: request, parse: { _ in }, mapError: mapError)
1819
}
1920
}
2021

21-
extension ResourceWithError where Model == Void {
22+
public extension Resource where Model == Void, E: NetworkErrorConvertible {
2223

2324
/// Creates an instace of Resource where the result type is `Void`
2425
///
2526
/// - Parameters:
2627
/// - request: The request to get the remote data payload
27-
/// - mapError: a closure which maps to Error
28-
public init(request: URLRequest, mapError: @escaping (_ networkError: NetworkError) -> E) {
29-
self.init(request: request, parse: { _ in }, mapError: mapError)
28+
init(request: URLRequest) {
29+
self.init(request: request, parse: { _ in }, mapError: { E(networkError: $0) })
3030
}
31+
3132
}

0 commit comments

Comments
 (0)