Skip to content

Commit

Permalink
fix: replace to HTTPTypes Components from Helpers Components (#564)
Browse files Browse the repository at this point in the history
* add HTTPTypes

* replace to HTTPFields from HTTPHeader

* replace to HTTPTypes.HTTPRequest.Method from HTTPMethod

* fix Test

* add setHeader(name: String, value: String) -> Self
  • Loading branch information
zunda-pixel authored Oct 14, 2024
1 parent 5786dd6 commit 71dee2a
Show file tree
Hide file tree
Showing 31 changed files with 242 additions and 381 deletions.
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
"version" : "1.3.3"
}
},
{
"identity" : "swift-http-types",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-http-types",
"state" : {
"revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd",
"version" : "1.3.0"
}
},
{
"identity" : "swift-snapshot-testing",
"kind" : "remoteSourceControl",
Expand Down
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ let package = Package(
.library(name: "Supabase", targets: ["Supabase", "Functions", "PostgREST", "Auth", "Realtime", "Storage"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-http-types.git", from: "1.3.0"),
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0" ..< "4.0.0"),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.1.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"),
Expand All @@ -33,6 +34,7 @@ let package = Package(
name: "Helpers",
dependencies: [
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "HTTPTypes", package: "swift-http-types"),
]
),
.testTarget(
Expand Down
10 changes: 8 additions & 2 deletions Sources/Auth/AuthAdmin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Foundation
import Helpers
import HTTPTypes

public struct AuthAdmin: Sendable {
let clientID: AuthClientID
Expand Down Expand Up @@ -62,10 +63,10 @@ public struct AuthAdmin: Sendable {
users: response.users,
aud: response.aud,
lastPage: 0,
total: httpResponse.headers["x-total-count"].flatMap(Int.init) ?? 0
total: httpResponse.headers[.xTotalCount].flatMap(Int.init) ?? 0
)

let links = httpResponse.headers["link"]?.components(separatedBy: ",") ?? []
let links = httpResponse.headers[.link]?.components(separatedBy: ",") ?? []
if !links.isEmpty {
for link in links {
let page = link.components(separatedBy: ";")[0].components(separatedBy: "=")[1].prefix(while: \.isNumber)
Expand All @@ -82,3 +83,8 @@ public struct AuthAdmin: Sendable {
return pagination
}
}

extension HTTPField.Name {
static let xTotalCount = Self("x-total-count")!
static let link = Self("link")!
}
6 changes: 3 additions & 3 deletions Sources/Auth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ public final class AuthClient: Sendable {
.init(
url: configuration.url.appendingPathComponent("user"),
method: .get,
headers: ["Authorization": "\(tokenType) \(accessToken)"]
headers: [.authorization: "\(tokenType) \(accessToken)"]
)
).decoded(as: User.self, decoder: configuration.decoder)

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

if let jwt {
request.headers["Authorization"] = "Bearer \(jwt)"
request.headers[.authorization] = "Bearer \(jwt)"
return try await api.execute(request).decoded(decoder: configuration.decoder)
}

Expand Down
19 changes: 10 additions & 9 deletions Sources/Auth/Internal/APIClient.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import Helpers
import HTTPTypes

extension HTTPClient {
init(configuration: AuthClient.Configuration) {
Expand Down Expand Up @@ -31,12 +32,12 @@ struct APIClient: Sendable {
Dependencies[clientID].http
}

func execute(_ request: HTTPRequest) async throws -> HTTPResponse {
func execute(_ request: Helpers.HTTPRequest) async throws -> Helpers.HTTPResponse {
var request = request
request.headers = HTTPHeaders(configuration.headers).merged(with: request.headers)
request.headers = HTTPFields(configuration.headers).merging(with: request.headers)

if request.headers[API_VERSION_HEADER_NAME] == nil {
request.headers[API_VERSION_HEADER_NAME] = API_VERSIONS[._20240101]!.name.rawValue
if request.headers[.apiVersionHeaderName] == nil {
request.headers[.apiVersionHeaderName] = API_VERSIONS[._20240101]!.name.rawValue
}

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

@discardableResult
func authorizedExecute(_ request: HTTPRequest) async throws -> HTTPResponse {
func authorizedExecute(_ request: Helpers.HTTPRequest) async throws -> Helpers.HTTPResponse {
var sessionManager: SessionManager {
Dependencies[clientID].sessionManager
}

let session = try await sessionManager.session()

var request = request
request.headers["Authorization"] = "Bearer \(session.accessToken)"
request.headers[.authorization] = "Bearer \(session.accessToken)"

return try await execute(request)
}

func handleError(response: HTTPResponse) -> AuthError {
func handleError(response: Helpers.HTTPResponse) -> AuthError {
guard let error = try? response.decoded(
as: _RawAPIErrorResponse.self,
decoder: configuration.decoder
Expand Down Expand Up @@ -105,8 +106,8 @@ struct APIClient: Sendable {
}
}

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

let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
Expand Down
6 changes: 6 additions & 0 deletions Sources/Auth/Internal/Contants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
//

import Foundation
import HTTPTypes

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

let API_VERSION_HEADER_NAME = "X-Supabase-Api-Version"

extension HTTPField.Name {
static let apiVersionHeaderName = HTTPField.Name(API_VERSION_HEADER_NAME)!
}

let API_VERSIONS: [APIVersion.Name: APIVersion] = [
._20240101: ._20240101,
]
Expand Down
25 changes: 13 additions & 12 deletions Sources/Functions/FunctionsClient.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ConcurrencyExtras
import Foundation
import Helpers
import HTTPTypes

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

struct MutableState {
/// Headers to be included in the requests.
var headers = HTTPHeaders()
var headers = HTTPFields()
}

private let mutableState = LockIsolated(MutableState())

var headers: HTTPHeaders {
var headers: HTTPFields {
mutableState.headers
}

Expand Down Expand Up @@ -71,9 +72,9 @@ public final class FunctionsClient: Sendable {
self.http = http

mutableState.withValue {
$0.headers = HTTPHeaders(headers)
if $0.headers["X-Client-Info"] == nil {
$0.headers["X-Client-Info"] = "functions-swift/\(version)"
$0.headers = HTTPFields(headers)
if $0.headers[.xClientInfo] == nil {
$0.headers[.xClientInfo] = "functions-swift/\(version)"
}
}
}
Expand Down Expand Up @@ -102,9 +103,9 @@ public final class FunctionsClient: Sendable {
public func setAuth(token: String?) {
mutableState.withValue {
if let token {
$0.headers["Authorization"] = "Bearer \(token)"
$0.headers[.authorization] = "Bearer \(token)"
} else {
$0.headers["Authorization"] = nil
$0.headers[.authorization] = nil
}
}
}
Expand Down Expand Up @@ -160,15 +161,15 @@ public final class FunctionsClient: Sendable {
private func rawInvoke(
functionName: String,
invokeOptions: FunctionInvokeOptions
) async throws -> HTTPResponse {
) async throws -> Helpers.HTTPResponse {
let request = buildRequest(functionName: functionName, options: invokeOptions)
let response = try await http.send(request)

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

let isRelayError = response.headers["x-relay-error"] == "true"
let isRelayError = response.headers[.xRelayError] == "true"
if isRelayError {
throw FunctionsError.relayError
}
Expand Down Expand Up @@ -211,17 +212,17 @@ public final class FunctionsClient: Sendable {
return stream
}

private func buildRequest(functionName: String, options: FunctionInvokeOptions) -> HTTPRequest {
private func buildRequest(functionName: String, options: FunctionInvokeOptions) -> Helpers.HTTPRequest {
var request = HTTPRequest(
url: url.appendingPathComponent(functionName),
method: options.httpMethod ?? .post,
query: options.query,
headers: mutableState.headers.merged(with: options.headers),
headers: mutableState.headers.merging(with: options.headers),
body: options.body
)

if let region = options.region ?? region {
request.headers["x-region"] = region
request.headers[.xRegion] = region
}

return request
Expand Down
17 changes: 9 additions & 8 deletions Sources/Functions/Types.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import Helpers
import HTTPTypes

/// An error type representing various errors that can occur while invoking functions.
public enum FunctionsError: Error, LocalizedError {
Expand All @@ -24,7 +25,7 @@ public struct FunctionInvokeOptions: Sendable {
/// Method to use in the function invocation.
let method: Method?
/// Headers to be included in the function invocation.
let headers: HTTPHeaders
let headers: HTTPFields
/// Body data to be sent with the function invocation.
let body: Data?
/// The Region to invoke the function in.
Expand All @@ -48,23 +49,23 @@ public struct FunctionInvokeOptions: Sendable {
region: String? = nil,
body: some Encodable
) {
var defaultHeaders = HTTPHeaders()
var defaultHeaders = HTTPFields()

switch body {
case let string as String:
defaultHeaders["Content-Type"] = "text/plain"
defaultHeaders[.contentType] = "text/plain"
self.body = string.data(using: .utf8)
case let data as Data:
defaultHeaders["Content-Type"] = "application/octet-stream"
defaultHeaders[.contentType] = "application/octet-stream"
self.body = data
default:
// default, assume this is JSON
defaultHeaders["Content-Type"] = "application/json"
defaultHeaders[.contentType] = "application/json"
self.body = try? JSONEncoder().encode(body)
}

self.method = method
self.headers = defaultHeaders.merged(with: HTTPHeaders(headers))
self.headers = defaultHeaders.merging(with: HTTPFields(headers))
self.region = region
self.query = query
}
Expand All @@ -84,7 +85,7 @@ public struct FunctionInvokeOptions: Sendable {
region: String? = nil
) {
self.method = method
self.headers = HTTPHeaders(headers)
self.headers = HTTPFields(headers)
self.region = region
self.query = query
body = nil
Expand All @@ -98,7 +99,7 @@ public struct FunctionInvokeOptions: Sendable {
case delete = "DELETE"
}

var httpMethod: HTTPMethod? {
var httpMethod: HTTPTypes.HTTPRequest.Method? {
switch method {
case .get:
.get
Expand Down
37 changes: 37 additions & 0 deletions Sources/Helpers/HTTP/HTTPFields.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import HTTPTypes

package extension HTTPFields {
init(_ dictionary: [String: String]) {
self.init(dictionary.map { .init(name: .init($0.key)!, value: $0.value) })
}

var dictionary: [String: String] {
let keyValues = self.map {
($0.name.rawName, $0.value)
}

return .init(keyValues, uniquingKeysWith: { $1 })
}

mutating func merge(with other: Self) {
for field in other {
self[field.name] = field.value
}
}

func merging(with other: Self) -> Self {
var copy = self

for field in other {
copy[field.name] = field.value
}

return copy
}
}

package extension HTTPField.Name {
static let xClientInfo = HTTPField.Name("X-Client-Info")!
static let xRegion = HTTPField.Name("x-region")!
static let xRelayError = HTTPField.Name("x-relay-error")!
}
Loading

0 comments on commit 71dee2a

Please sign in to comment.