Skip to content

Commit 71dee2a

Browse files
authored
fix: replace to HTTPTypes Components from Helpers Components (#564)
* add HTTPTypes * replace to HTTPFields from HTTPHeader * replace to HTTPTypes.HTTPRequest.Method from HTTPMethod * fix Test * add setHeader(name: String, value: String) -> Self
1 parent 5786dd6 commit 71dee2a

31 files changed

+242
-381
lines changed

Package.resolved

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727
"version" : "1.3.3"
2828
}
2929
},
30+
{
31+
"identity" : "swift-http-types",
32+
"kind" : "remoteSourceControl",
33+
"location" : "https://github.com/apple/swift-http-types",
34+
"state" : {
35+
"revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd",
36+
"version" : "1.3.0"
37+
}
38+
},
3039
{
3140
"identity" : "swift-snapshot-testing",
3241
"kind" : "remoteSourceControl",

Package.swift

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ let package = Package(
2222
.library(name: "Supabase", targets: ["Supabase", "Functions", "PostgREST", "Auth", "Realtime", "Storage"]),
2323
],
2424
dependencies: [
25+
.package(url: "https://github.com/apple/swift-http-types.git", from: "1.3.0"),
2526
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "4.0.0"),
2627
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.1.0"),
2728
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"),
@@ -33,6 +34,7 @@ let package = Package(
3334
name: "Helpers",
3435
dependencies: [
3536
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
37+
.product(name: "HTTPTypes", package: "swift-http-types"),
3638
]
3739
),
3840
.testTarget(

Sources/Auth/AuthAdmin.swift

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import Foundation
99
import Helpers
10+
import HTTPTypes
1011

1112
public struct AuthAdmin: Sendable {
1213
let clientID: AuthClientID
@@ -62,10 +63,10 @@ public struct AuthAdmin: Sendable {
6263
users: response.users,
6364
aud: response.aud,
6465
lastPage: 0,
65-
total: httpResponse.headers["x-total-count"].flatMap(Int.init) ?? 0
66+
total: httpResponse.headers[.xTotalCount].flatMap(Int.init) ?? 0
6667
)
6768

68-
let links = httpResponse.headers["link"]?.components(separatedBy: ",") ?? []
69+
let links = httpResponse.headers[.link]?.components(separatedBy: ",") ?? []
6970
if !links.isEmpty {
7071
for link in links {
7172
let page = link.components(separatedBy: ";")[0].components(separatedBy: "=")[1].prefix(while: \.isNumber)
@@ -82,3 +83,8 @@ public struct AuthAdmin: Sendable {
8283
return pagination
8384
}
8485
}
86+
87+
extension HTTPField.Name {
88+
static let xTotalCount = Self("x-total-count")!
89+
static let link = Self("link")!
90+
}

Sources/Auth/AuthClient.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ public final class AuthClient: Sendable {
716716
.init(
717717
url: configuration.url.appendingPathComponent("user"),
718718
method: .get,
719-
headers: ["Authorization": "\(tokenType) \(accessToken)"]
719+
headers: [.authorization: "\(tokenType) \(accessToken)"]
720720
)
721721
).decoded(as: User.self, decoder: configuration.decoder)
722722

@@ -803,7 +803,7 @@ public final class AuthClient: Sendable {
803803
url: configuration.url.appendingPathComponent("logout"),
804804
method: .post,
805805
query: [URLQueryItem(name: "scope", value: scope.rawValue)],
806-
headers: [.init(name: "Authorization", value: "Bearer \(accessToken)")]
806+
headers: [.authorization: "Bearer \(accessToken)"]
807807
)
808808
)
809809
} catch let AuthError.api(_, _, _, response) where [404, 403, 401].contains(response.statusCode) {
@@ -982,7 +982,7 @@ public final class AuthClient: Sendable {
982982
var request = HTTPRequest(url: configuration.url.appendingPathComponent("user"), method: .get)
983983

984984
if let jwt {
985-
request.headers["Authorization"] = "Bearer \(jwt)"
985+
request.headers[.authorization] = "Bearer \(jwt)"
986986
return try await api.execute(request).decoded(decoder: configuration.decoder)
987987
}
988988

Sources/Auth/Internal/APIClient.swift

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Foundation
22
import Helpers
3+
import HTTPTypes
34

45
extension HTTPClient {
56
init(configuration: AuthClient.Configuration) {
@@ -31,12 +32,12 @@ struct APIClient: Sendable {
3132
Dependencies[clientID].http
3233
}
3334

34-
func execute(_ request: HTTPRequest) async throws -> HTTPResponse {
35+
func execute(_ request: Helpers.HTTPRequest) async throws -> Helpers.HTTPResponse {
3536
var request = request
36-
request.headers = HTTPHeaders(configuration.headers).merged(with: request.headers)
37+
request.headers = HTTPFields(configuration.headers).merging(with: request.headers)
3738

38-
if request.headers[API_VERSION_HEADER_NAME] == nil {
39-
request.headers[API_VERSION_HEADER_NAME] = API_VERSIONS[._20240101]!.name.rawValue
39+
if request.headers[.apiVersionHeaderName] == nil {
40+
request.headers[.apiVersionHeaderName] = API_VERSIONS[._20240101]!.name.rawValue
4041
}
4142

4243
let response = try await http.send(request)
@@ -49,20 +50,20 @@ struct APIClient: Sendable {
4950
}
5051

5152
@discardableResult
52-
func authorizedExecute(_ request: HTTPRequest) async throws -> HTTPResponse {
53+
func authorizedExecute(_ request: Helpers.HTTPRequest) async throws -> Helpers.HTTPResponse {
5354
var sessionManager: SessionManager {
5455
Dependencies[clientID].sessionManager
5556
}
5657

5758
let session = try await sessionManager.session()
5859

5960
var request = request
60-
request.headers["Authorization"] = "Bearer \(session.accessToken)"
61+
request.headers[.authorization] = "Bearer \(session.accessToken)"
6162

6263
return try await execute(request)
6364
}
6465

65-
func handleError(response: HTTPResponse) -> AuthError {
66+
func handleError(response: Helpers.HTTPResponse) -> AuthError {
6667
guard let error = try? response.decoded(
6768
as: _RawAPIErrorResponse.self,
6869
decoder: configuration.decoder
@@ -105,8 +106,8 @@ struct APIClient: Sendable {
105106
}
106107
}
107108

108-
private func parseResponseAPIVersion(_ response: HTTPResponse) -> Date? {
109-
guard let apiVersion = response.headers[API_VERSION_HEADER_NAME] else { return nil }
109+
private func parseResponseAPIVersion(_ response: Helpers.HTTPResponse) -> Date? {
110+
guard let apiVersion = response.headers[.apiVersionHeaderName] else { return nil }
110111

111112
let formatter = ISO8601DateFormatter()
112113
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]

Sources/Auth/Internal/Contants.swift

+6
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@
66
//
77

88
import Foundation
9+
import HTTPTypes
910

1011
let EXPIRY_MARGIN: TimeInterval = 30
1112
let STORAGE_KEY = "supabase.auth.token"
1213

1314
let API_VERSION_HEADER_NAME = "X-Supabase-Api-Version"
15+
16+
extension HTTPField.Name {
17+
static let apiVersionHeaderName = HTTPField.Name(API_VERSION_HEADER_NAME)!
18+
}
19+
1420
let API_VERSIONS: [APIVersion.Name: APIVersion] = [
1521
._20240101: ._20240101,
1622
]

Sources/Functions/FunctionsClient.swift

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ConcurrencyExtras
22
import Foundation
33
import Helpers
4+
import HTTPTypes
45

56
#if canImport(FoundationNetworking)
67
import FoundationNetworking
@@ -25,12 +26,12 @@ public final class FunctionsClient: Sendable {
2526

2627
struct MutableState {
2728
/// Headers to be included in the requests.
28-
var headers = HTTPHeaders()
29+
var headers = HTTPFields()
2930
}
3031

3132
private let mutableState = LockIsolated(MutableState())
3233

33-
var headers: HTTPHeaders {
34+
var headers: HTTPFields {
3435
mutableState.headers
3536
}
3637

@@ -71,9 +72,9 @@ public final class FunctionsClient: Sendable {
7172
self.http = http
7273

7374
mutableState.withValue {
74-
$0.headers = HTTPHeaders(headers)
75-
if $0.headers["X-Client-Info"] == nil {
76-
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
75+
$0.headers = HTTPFields(headers)
76+
if $0.headers[.xClientInfo] == nil {
77+
$0.headers[.xClientInfo] = "functions-swift/\(version)"
7778
}
7879
}
7980
}
@@ -102,9 +103,9 @@ public final class FunctionsClient: Sendable {
102103
public func setAuth(token: String?) {
103104
mutableState.withValue {
104105
if let token {
105-
$0.headers["Authorization"] = "Bearer \(token)"
106+
$0.headers[.authorization] = "Bearer \(token)"
106107
} else {
107-
$0.headers["Authorization"] = nil
108+
$0.headers[.authorization] = nil
108109
}
109110
}
110111
}
@@ -160,15 +161,15 @@ public final class FunctionsClient: Sendable {
160161
private func rawInvoke(
161162
functionName: String,
162163
invokeOptions: FunctionInvokeOptions
163-
) async throws -> HTTPResponse {
164+
) async throws -> Helpers.HTTPResponse {
164165
let request = buildRequest(functionName: functionName, options: invokeOptions)
165166
let response = try await http.send(request)
166167

167168
guard 200 ..< 300 ~= response.statusCode else {
168169
throw FunctionsError.httpError(code: response.statusCode, data: response.data)
169170
}
170171

171-
let isRelayError = response.headers["x-relay-error"] == "true"
172+
let isRelayError = response.headers[.xRelayError] == "true"
172173
if isRelayError {
173174
throw FunctionsError.relayError
174175
}
@@ -211,17 +212,17 @@ public final class FunctionsClient: Sendable {
211212
return stream
212213
}
213214

214-
private func buildRequest(functionName: String, options: FunctionInvokeOptions) -> HTTPRequest {
215+
private func buildRequest(functionName: String, options: FunctionInvokeOptions) -> Helpers.HTTPRequest {
215216
var request = HTTPRequest(
216217
url: url.appendingPathComponent(functionName),
217218
method: options.httpMethod ?? .post,
218219
query: options.query,
219-
headers: mutableState.headers.merged(with: options.headers),
220+
headers: mutableState.headers.merging(with: options.headers),
220221
body: options.body
221222
)
222223

223224
if let region = options.region ?? region {
224-
request.headers["x-region"] = region
225+
request.headers[.xRegion] = region
225226
}
226227

227228
return request

Sources/Functions/Types.swift

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Foundation
22
import Helpers
3+
import HTTPTypes
34

45
/// An error type representing various errors that can occur while invoking functions.
56
public enum FunctionsError: Error, LocalizedError {
@@ -24,7 +25,7 @@ public struct FunctionInvokeOptions: Sendable {
2425
/// Method to use in the function invocation.
2526
let method: Method?
2627
/// Headers to be included in the function invocation.
27-
let headers: HTTPHeaders
28+
let headers: HTTPFields
2829
/// Body data to be sent with the function invocation.
2930
let body: Data?
3031
/// The Region to invoke the function in.
@@ -48,23 +49,23 @@ public struct FunctionInvokeOptions: Sendable {
4849
region: String? = nil,
4950
body: some Encodable
5051
) {
51-
var defaultHeaders = HTTPHeaders()
52+
var defaultHeaders = HTTPFields()
5253

5354
switch body {
5455
case let string as String:
55-
defaultHeaders["Content-Type"] = "text/plain"
56+
defaultHeaders[.contentType] = "text/plain"
5657
self.body = string.data(using: .utf8)
5758
case let data as Data:
58-
defaultHeaders["Content-Type"] = "application/octet-stream"
59+
defaultHeaders[.contentType] = "application/octet-stream"
5960
self.body = data
6061
default:
6162
// default, assume this is JSON
62-
defaultHeaders["Content-Type"] = "application/json"
63+
defaultHeaders[.contentType] = "application/json"
6364
self.body = try? JSONEncoder().encode(body)
6465
}
6566

6667
self.method = method
67-
self.headers = defaultHeaders.merged(with: HTTPHeaders(headers))
68+
self.headers = defaultHeaders.merging(with: HTTPFields(headers))
6869
self.region = region
6970
self.query = query
7071
}
@@ -84,7 +85,7 @@ public struct FunctionInvokeOptions: Sendable {
8485
region: String? = nil
8586
) {
8687
self.method = method
87-
self.headers = HTTPHeaders(headers)
88+
self.headers = HTTPFields(headers)
8889
self.region = region
8990
self.query = query
9091
body = nil
@@ -98,7 +99,7 @@ public struct FunctionInvokeOptions: Sendable {
9899
case delete = "DELETE"
99100
}
100101

101-
var httpMethod: HTTPMethod? {
102+
var httpMethod: HTTPTypes.HTTPRequest.Method? {
102103
switch method {
103104
case .get:
104105
.get

Sources/Helpers/HTTP/HTTPFields.swift

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import HTTPTypes
2+
3+
package extension HTTPFields {
4+
init(_ dictionary: [String: String]) {
5+
self.init(dictionary.map { .init(name: .init($0.key)!, value: $0.value) })
6+
}
7+
8+
var dictionary: [String: String] {
9+
let keyValues = self.map {
10+
($0.name.rawName, $0.value)
11+
}
12+
13+
return .init(keyValues, uniquingKeysWith: { $1 })
14+
}
15+
16+
mutating func merge(with other: Self) {
17+
for field in other {
18+
self[field.name] = field.value
19+
}
20+
}
21+
22+
func merging(with other: Self) -> Self {
23+
var copy = self
24+
25+
for field in other {
26+
copy[field.name] = field.value
27+
}
28+
29+
return copy
30+
}
31+
}
32+
33+
package extension HTTPField.Name {
34+
static let xClientInfo = HTTPField.Name("X-Client-Info")!
35+
static let xRegion = HTTPField.Name("x-region")!
36+
static let xRelayError = HTTPField.Name("x-relay-error")!
37+
}

0 commit comments

Comments
 (0)