krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

v2: Hutch/Networking/SRHTError.swift · raw

 1import Foundation
 2
 3/// Errors produced by the Sourcehut GraphQL client.
 4enum SRHTError: LocalizedError, Sendable {
 5    /// The server returned one or more GraphQL-level errors.
 6    case graphQLErrors([GraphQLError])
 7    /// The HTTP response had a non-2xx status code.
 8    case httpError(Int)
 9    /// The client refused to send credentials to an unexpected URL.
10    case invalidAuthenticatedURL(URL)
11    /// The response data could not be decoded.
12    case decodingError(any Error)
13    /// A networking error from URLSession (timeout, DNS, connectivity, etc.).
14    case networkError(any Error)
15    /// 401 or no authentication token configured.
16    case unauthorized
17
18    var errorDescription: String? {
19        switch self {
20        case .graphQLErrors(let errors):
21            let messages = errors.map(\.message).joined(separator: "\n")
22            return "GraphQL error: \(messages)"
23        case .httpError(let code):
24            return "Server returned HTTP \(code)."
25        case .invalidAuthenticatedURL(let url):
26            return "Refused to authenticate request to unexpected URL: \(url.absoluteString)"
27        case .decodingError(let error):
28            return "Failed to decode response: \(error.localizedDescription)"
29        case .networkError(let error):
30            return "Network error: \(error.localizedDescription)"
31        case .unauthorized:
32            return "Authentication required. Please sign in again."
33        }
34    }
35
36    /// Whether this error represents a connectivity issue (no internet, timeout, DNS).
37    var isConnectivityError: Bool {
38        switch self {
39        case .networkError(let error):
40            let nsError = error as NSError
41            let connectivityCodes: Set<Int> = [
42                NSURLErrorNotConnectedToInternet,
43                NSURLErrorNetworkConnectionLost,
44                NSURLErrorTimedOut,
45                NSURLErrorCannotFindHost,
46                NSURLErrorCannotConnectToHost,
47                NSURLErrorDNSLookupFailed,
48                NSURLErrorInternationalRoamingOff,
49                NSURLErrorDataNotAllowed
50            ]
51            return connectivityCodes.contains(nsError.code)
52        default:
53            return false
54        }
55    }
56}
57
58/// A single error entry from the GraphQL `errors` array.
59struct GraphQLError: Decodable, Sendable {
60    let message: String
61    let locations: [GraphQLErrorLocation]?
62}
63
64struct GraphQLErrorLocation: Decodable, Sendable {
65    let line: Int
66    let column: Int
67}