a native ios client for gitbay

client ios swift

https://gitbay.org

gitbay/Networking/GitbayError.swift

65 lines · 2700 bytes

 1import Foundation
 2
 3/// A failure from either API surface, already mapped off the exit code so
 4/// callers switch on meaning rather than on numbers.
 5///
 6///     exit  http  case
 7///        2   400  usage         a bug in the app
 8///        3   404  notFound      an empty state, not an error banner
 9///        4   403  denied        the message explains the rule; show it verbatim
10///     1, 5   500  failure       retried once by the client, then surfaced
11///           401  unauthorized  the token is invalid, expired or revoked
12///           429  rateLimited   Retry-After was longer than the client will wait
13nonisolated enum GitbayError: LocalizedError, Sendable {
14    case usage(String)
15    case notFound(String)
16    case denied(String)
17    case failure(String)
18    case unauthorized(String)
19    case rateLimited(retryAfter: TimeInterval)
20    /// The command exists but is not read-only, so it cannot be reached
21    /// with GET. Also an app bug: it means we routed a write through `read`.
22    case notReadable(String)
23    case transport(any Error)
24    case decoding(any Error)
25    /// A major protocol version the app does not understand.
26    case protocolMismatch(Int)
27    /// The client refused to send the token somewhere other than the instance.
28    case unexpectedHost(URL)
29
30    /// Text for a person. `denied` and `notFound` come from the server
31    /// verbatim  those messages exist to explain a rule, and rewording
32    /// them loses the explanation.
33    var userFacingMessage: String {
34        switch self {
35        case .denied(let message), .notFound(let message):
36            message
37        case .unauthorized:
38            "Your token is no longer valid. Sign in again."
39        case .rateLimited(let seconds):
40            "Too many requests. Try again in \(Int(seconds.rounded()))s."
41        case .failure(let message):
42            message.isEmpty ? "The server could not complete that." : message
43        case .transport:
44            "Check your connection and try again."
45        // A usage or protocol failure is ours, not the user's. argv never
46        // reaches the screen.
47        case .usage, .notReadable, .decoding, .protocolMismatch, .unexpectedHost:
48            "Something went wrong. Please try again."
49        }
50    }
51
52    var errorDescription: String? { userFacingMessage }
53
54    /// True when the right response is an empty screen rather than a banner.
55    var isEmptyState: Bool {
56        if case .notFound = self { return true }
57        return false
58    }
59
60    /// True when the token needs replacing and the app should sign out.
61    var requiresReauthentication: Bool {
62        if case .unauthorized = self { return true }
63        return false
64    }
65}