• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supabase-swift / 17321717294

29 Aug 2025 10:44AM UTC coverage: 78.634% (+1.2%) from 77.386%
17321717294

Pull #781

github

web-flow
Merge 80b20054e into e4d8c3718
Pull Request #781: RFC: Migrate HTTP networking from URLSession to Alamofire

1027 of 1123 new or added lines in 27 files covered. (91.45%)

27 existing lines in 8 files now uncovered.

5156 of 6557 relevant lines covered (78.63%)

29.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.93
/Sources/Auth/Internal/APIClient.swift
1
import Alamofire
2
import Foundation
3

4
struct NoopParameter: Encodable, Sendable {}
5

6
struct APIClient: Sendable {
7
  let clientID: AuthClientID
8

9
  var configuration: AuthClient.Configuration {
51✔
10
    Dependencies[clientID].configuration
51✔
11
  }
51✔
12

13
  var session: Alamofire.Session {
65✔
14
    Dependencies[clientID].session
65✔
15
  }
65✔
16

NEW
17
  private let urlQueryEncoder: any ParameterEncoding = URLEncoding.queryString
×
18
  private var defaultEncoder: any ParameterEncoder {
46✔
19
    JSONParameterEncoder(encoder: configuration.encoder)
46✔
20
  }
46✔
21

22
  func execute<RequestBody: Encodable & Sendable>(
23
    _ url: URL,
24
    method: HTTPMethod = .get,
25
    headers: HTTPHeaders = [:],
26
    query: Parameters? = nil,
27
    body: RequestBody? = NoopParameter(),
28
    encoder: (any ParameterEncoder)? = nil
29
  ) throws -> DataRequest {
65✔
30
    var request = try URLRequest(url: url, method: method, headers: headers)
65✔
31

65✔
32
    request = try urlQueryEncoder.encode(request, with: query)
65✔
33
    if RequestBody.self != NoopParameter.self {
65✔
34
      request = try (encoder ?? defaultEncoder).encode(body, into: request)
46✔
35
    }
65✔
36

65✔
37
    return session.request(request)
65✔
38
      .validate { _, response, data in
65✔
39
        guard 200..<300 ~= response.statusCode else {
64✔
40
          return .failure(handleError(response: response, data: data ?? Data()))
5✔
41
        }
59✔
42
        return .success(())
59✔
43
      }
64✔
44
  }
65✔
45

46
  func handleError(response: HTTPURLResponse, data: Data) -> AuthError {
5✔
47
    guard
5✔
48
      let error = try? configuration.decoder.decode(
5✔
49
        _RawAPIErrorResponse.self,
5✔
50
        from: data
5✔
51
      )
5✔
52
    else {
5✔
53
      return .api(
3✔
54
        message: "Unexpected error",
3✔
55
        errorCode: .unexpectedFailure,
3✔
56
        underlyingData: data,
3✔
57
        underlyingResponse: response
3✔
58
      )
3✔
59
    }
3✔
60

2✔
61
    let responseAPIVersion = parseResponseAPIVersion(response)
2✔
62

2✔
63
    let errorCode: ErrorCode? =
2✔
64
      if let responseAPIVersion, responseAPIVersion >= apiVersions[._20240101]!.timestamp,
2✔
65
        let code = error.code
2✔
66
      {
2✔
67
        ErrorCode(code)
×
68
      } else {
2✔
69
        error.errorCode
2✔
70
      }
2✔
71

2✔
72
    if errorCode == nil, let weakPassword = error.weakPassword {
2✔
73
      return .weakPassword(
×
74
        message: error._getErrorMessage(),
×
75
        reasons: weakPassword.reasons ?? []
×
76
      )
×
77
    } else if errorCode == .weakPassword {
2✔
78
      return .weakPassword(
×
79
        message: error._getErrorMessage(),
×
80
        reasons: error.weakPassword?.reasons ?? []
×
81
      )
×
82
    } else if errorCode == .sessionNotFound {
2✔
83
      return .sessionMissing
×
84
    } else {
2✔
85
      return .api(
2✔
86
        message: error._getErrorMessage(),
2✔
87
        errorCode: errorCode ?? .unknown,
2✔
88
        underlyingData: data,
2✔
89
        underlyingResponse: response
2✔
90
      )
2✔
91
    }
2✔
92
  }
2✔
93

94
  private func parseResponseAPIVersion(_ response: HTTPURLResponse) -> Date? {
2✔
95
    guard let apiVersion = response.headers[apiVersionHeaderNameHeaderKey] else { return nil }
2✔
96

×
97
    let formatter = ISO8601DateFormatter()
×
98
    formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
×
99
    return formatter.date(from: "\(apiVersion)T00:00:00.0Z")
×
100
  }
2✔
101
}
102

103
// Struct for mapping all fields possibly returned by API.
104
struct _RawAPIErrorResponse: Decodable {
105
  let msg: String?
106
  let message: String?
107
  let errorDescription: String?
108
  let error: String?
109
  let code: String?
110
  let errorCode: ErrorCode?
111
  let weakPassword: _WeakPassword?
112

113
  struct _WeakPassword: Decodable {
114
    let reasons: [String]?
115
  }
116

117
  func _getErrorMessage() -> String {
2✔
118
    msg ?? message ?? errorDescription ?? error ?? "Unknown"
2✔
119
  }
2✔
120
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc