-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathServerConfig.swift
93 lines (80 loc) · 3.53 KB
/
ServerConfig.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//
// ServerConfig.swift
// Networking
//
// Created by VG on 2024-11-13.
//
import Foundation
public protocol ServerConfigurable {
var baseURL: URL { get }
func header(forRequest request: Requestable) -> HTTP.Header
}
// MARK: -
public struct ServerConfig: ServerConfigurable {
// MARK: Private properties
private let additionalHeaders: HTTP.Header
// MARK: - Public properties
public let userAgent: String?
/// A provider for authorization tokens used to authenticate requests; `nil` if no authentication is needed.
public let tokenProvider: TokenProvidable?
/// The base URL for the server
public let baseURL: URL
// MARK: - Initialization
/// Initializes a new instance of `ServerConfigV2` with the specified configuration details.
/// - Parameters:
/// - baseURL: A `String` representing the base URL for the server. This URL will be used as the primary endpoint for all requests.
/// - userAgent: An optional `String` representing the user agent to include in the request headers. If not provided, it defaults to a string combining `name` and `version`.
/// - additionalHeaders: An optional dictionary of additional headers to be merged into the default headers for each request. The default value is an empty dictionary.
/// - tokenProvider: An optional `TokenProvidable` object used to authenticate requests. This provider supplies authorization tokens when required by a request. Defaults to `nil`, meaning no token is provided.
/// - Returns: A configured instance of `ServerConfigV2` with the specified parameters.
public init(
baseURL: URL,
userAgent: String? = "\(name)/\(version)",
additionalHeaders: HTTP.Header = [:],
tokenProvider: TokenProvidable? = nil
) {
self.baseURL = baseURL
self.userAgent = userAgent
self.additionalHeaders = additionalHeaders
self.tokenProvider = tokenProvider
}
}
// MARK: - Public functions
public extension ServerConfig {
func header(forRequest request: Requestable) -> HTTP.Header {
var headers = HTTP.Header()
// Base headers
if let host = baseURL.host { headers[HTTP.Header.Field.host] = host }
if let userAgent = userAgent { headers[HTTP.Header.Field.userAgent] = userAgent }
if let contentType = request.contentType { headers[HTTP.Header.Field.contentType] = contentType }
// Add any additional configured headers
headers.merge(additionalHeaders) { _, new in new }
guard let tokenProvider else { return headers }
switch tokenProvider.token {
case .success(let token):
guard let authHeader = authorizationHeader(for: request.authorization, token: token) else { break }
headers[HTTP.Header.Field.auth] = authHeader
case .failure: break
}
return headers
}
}
// MARK: - Convenience Initializers
public extension ServerConfig {
static func basic(baseURL: URL) -> ServerConfig {
.init(baseURL: baseURL)
}
static func authenticated(baseURL: URL, tokenProvider: TokenProvidable) -> ServerConfig {
.init(baseURL: baseURL, tokenProvider: tokenProvider)
}
}
// MARK: - Private functions
private extension ServerConfig {
func authorizationHeader(for type: Request.Authorization, token: String) -> String? {
switch type {
case .bearer: return String(format: HTTP.Header.Field.bearer, token)
case .basic: return String(format: HTTP.Header.Field.basic, token)
case .none: return nil
}
}
}