Skip to content

Commit 8e2d413

Browse files
committed
🚧 🧪 Prepares for basic retrier. Polishes tests.
- Adds previousAttempts in preparation for basic retrier. - Adds tests that validate previousAttempts is correctly incremented. - Adds updates plugin handlers to all through, matching their protocol. - Adds tests that validate throwing errors rethrows up correctly. - Replaces unused closure parameters with underscore to reduce noise.
1 parent b735606 commit 8e2d413

File tree

9 files changed

+299
-81
lines changed

9 files changed

+299
-81
lines changed

Sources/HTTPNetworking/HTTPRequest.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import Foundation
1919
/// You can retry the ``HTTPRequest`` if it fails by calling ``retry(_:)`` or ``retry(with:)``.
2020
/// By providing a ``RetryHandler`` or ``HTTPRequestRetrier``, you can determine if a request should be retried if it fails.
2121
/// Typical use cases include retrying requests a given number of times in the event of poor network connectivity.
22-
public class HTTPRequest<T: Decodable> {
22+
public class HTTPRequest<Value: Decodable> {
2323

2424
// MARK: Properties
2525

@@ -61,10 +61,14 @@ public class HTTPRequest<T: Decodable> {
6161

6262
// MARK: Execution
6363

64-
/// Triggers the request to actually be sent.
65-
public func run() async throws -> T {
64+
/// Dispatches the request, returning the request's expected `Value`.
65+
public func run() async throws -> Value {
66+
try await execute(previousAttempts: 0)
67+
}
68+
69+
/// Executes the request to the dispatcher.
70+
private func execute(previousAttempts: Int) async throws -> Value {
6671
var request = self.request
67-
6872
do {
6973

7074
try Task.checkCancellation()
@@ -87,17 +91,24 @@ public class HTTPRequest<T: Decodable> {
8791
try Task.checkCancellation()
8892

8993
// Convert data to the expected type
90-
return try decoder.decode(T.self, from: data)
94+
return try decoder.decode(Value.self, from: data)
9195
} catch {
92-
let strategy = try await ZipRetrier(retriers).retry(request, for: dispatcher.session, dueTo: error)
96+
let previousAttempts = previousAttempts + 1
97+
let strategy = try await ZipRetrier(retriers).retry(
98+
request,
99+
for: dispatcher.session,
100+
dueTo: error,
101+
previousAttempts: previousAttempts
102+
)
103+
93104
switch strategy {
94105
case .concede:
95106
throw error
96107
case .retryAfterDelay(let delay):
97108
try await Task.sleep(for: delay)
98109
fallthrough
99110
case .retry:
100-
return try await run()
111+
return try await execute(previousAttempts: previousAttempts)
101112
}
102113
}
103114
}

Sources/HTTPNetworking/Plugins/HTTPRequestRetrier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Foundation
77
/// By conforming to ``HTTPRequestRetrier`` you can implement both simple and complex logic for retrying an ``HTTPRequest`` when
88
/// it fails. Common uses cases include retrying a given amount of times due to a specific error such as poor network connectivity.
99
public protocol HTTPRequestRetrier {
10-
func retry(_ request: URLRequest, for session: URLSession, dueTo error: Error) async throws -> RetryStrategy
10+
func retry(_ request: URLRequest, for session: URLSession, dueTo error: Error, previousAttempts: Int) async throws -> RetryStrategy
1111
}
1212

1313
// MARK: - RetryStrategy

Sources/HTTPNetworking/Plugins/Retriers/Retrier.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
public typealias RetryHandler = (URLRequest, URLSession, Error) async -> RetryStrategy
3+
public typealias RetryHandler = (URLRequest, URLSession, Error, Int) async throws -> RetryStrategy
44

55
/// An ``HTTPRequestRetrier`` that can be used to retry an ``HTTPRequest`` upon failure.
66
public struct Retrier: HTTPRequestRetrier {
@@ -21,8 +21,13 @@ public struct Retrier: HTTPRequestRetrier {
2121

2222
// MARK: ResponseValidator
2323

24-
public func retry(_ request: URLRequest, for session: URLSession, dueTo error: Error) async -> RetryStrategy {
25-
await handler(request, session, error)
24+
public func retry(
25+
_ request: URLRequest,
26+
for session: URLSession,
27+
dueTo error: Error,
28+
previousAttempts: Int
29+
) async throws -> RetryStrategy {
30+
try await handler(request, session, error, previousAttempts)
2631
}
2732
}
2833

Sources/HTTPNetworking/Plugins/Retriers/ZipRetrier.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,22 @@ public struct ZipRetrier: HTTPRequestRetrier {
2626

2727
// MARK: ResponseValidator
2828

29-
public func retry(_ request: URLRequest, for session: URLSession, dueTo error: Error) async throws -> RetryStrategy {
29+
public func retry(
30+
_ request: URLRequest,
31+
for session: URLSession,
32+
dueTo error: Error,
33+
previousAttempts: Int
34+
) async throws -> RetryStrategy {
3035
for retrier in retriers {
3136
try Task.checkCancellation()
3237

33-
let strategy = try await retrier.retry(request, for: session, dueTo: error)
38+
let strategy = try await retrier.retry(
39+
request,
40+
for: session,
41+
dueTo: error,
42+
previousAttempts: previousAttempts
43+
)
44+
3445
switch strategy {
3546
case .concede:
3647
continue

Sources/HTTPNetworking/Plugins/Validators/Validator.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
public typealias ValidationHandler = (HTTPURLResponse, URLRequest, Data) async -> ValidationResult
3+
public typealias ValidationHandler = (HTTPURLResponse, URLRequest, Data) async throws -> ValidationResult
44

55
/// An ``HTTPResponseValidator`` that can be used to validate a response from an ``HTTPRequest``.
66
public struct Validator: HTTPResponseValidator {
@@ -20,8 +20,8 @@ public struct Validator: HTTPResponseValidator {
2020

2121
// MARK: HTTPResponseValidator
2222

23-
public func validate(_ response: HTTPURLResponse, for request: URLRequest, with data: Data) async -> ValidationResult {
24-
await handler(response, request, data)
23+
public func validate(_ response: HTTPURLResponse, for request: URLRequest, with data: Data) async throws -> ValidationResult {
24+
try await handler(response, request, data)
2525
}
2626
}
2727

0 commit comments

Comments
 (0)