Skip to content

Commit acc32a0

Browse files
committed
Allow methods to inject additional headers when making CRUD calls
1 parent 4cf4934 commit acc32a0

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

Sources/ComposableArchitecturePattern/Server.swift

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,37 +46,44 @@ public protocol Server: Actor {
4646

4747
/// Sends a GET request and returns the specified value type from the given API.
4848
///
49+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
4950
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the specified return type is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
50-
func get<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
51+
func get<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
5152
/// Sends a POST request and returns the specified value type from the given API.
5253
///
54+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
5355
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the specified return type is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
54-
func post<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
56+
func post<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
5557

5658
/// Sends a POST request and returns the specified value type from the given API.
5759
///
60+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
5861
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the return type of `Bool` is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
59-
func post(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
62+
func post(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
6063

6164
/// Sends a PUT request and returns the specified value type from the given API.
6265
///
66+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
6367
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the specified return type is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
64-
func put<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
68+
func put<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
6569

6670
/// Sends a PUT request and returns the specified value type from the given API.
6771
///
72+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
6873
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the return type of `Bool` is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
69-
func put(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
74+
func put(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
7075

7176
/// Sends a DELETE request and returns the specified value type from the given API.
7277
///
78+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
7379
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the specified return type is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
74-
func delete<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
80+
func delete<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
7581

7682
/// Sends a DELETE request and returns the specified value type from the given API.
7783
///
84+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
7885
/// - Note: The server automatically checks against these values to check whether they're supported by the API or not. For instance, if the return type of `Bool` is not supported, a `ServerAPIError.badRequest` error is thrown. If the specified API doesn't support this function, a `ServerAPIError.badRequest` error is thrown.
79-
func delete(_ api: any ServerAPI, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
86+
func delete(_ api: any ServerAPI, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
8087

8188
/// Send the given request to the server and return the decoded object.
8289
/// - Returns: The given decoded type or an `APIError`.
@@ -99,7 +106,7 @@ public extension Server {
99106
}
100107

101108
// GETs
102-
func get<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
109+
func get<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
103110
if self.blockAllAPIsNotSupported {
104111
try self._checkAPIsContainAPI(api)
105112

@@ -119,7 +126,7 @@ public extension Server {
119126
throw ServerAPIError.taskCancelled(error: error)
120127
}
121128

122-
let request = try api.request(.GET, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
129+
let request = try api.request(.GET, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
123130
let decoded: T = try await self.sendRequest(request, requestUID: requestUID, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
124131

125132
do {
@@ -133,7 +140,7 @@ public extension Server {
133140
}
134141

135142
// POSTs
136-
func post<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
143+
func post<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
137144
if self.blockAllAPIsNotSupported {
138145
try self._checkAPIsContainAPI(api)
139146

@@ -152,7 +159,7 @@ public extension Server {
152159
throw ServerAPIError.taskCancelled(error: error)
153160
}
154161

155-
let request = try api.request(.POST, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
162+
let request = try api.request(.POST, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
156163
let decoded: T = try await self.sendRequest(request, requestUID: requestUID, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
157164

158165
do {
@@ -165,7 +172,7 @@ public extension Server {
165172
return decoded
166173
}
167174

168-
func post(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
175+
func post(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
169176
if self.blockAllAPIsNotSupported {
170177
try self._checkAPIsContainAPI(api)
171178
}
@@ -182,7 +189,7 @@ public extension Server {
182189
throw ServerAPIError.taskCancelled(error: error)
183190
}
184191

185-
let request = try api.request(.POST, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
192+
let request = try api.request(.POST, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
186193
let wasSuccessful = try await self.sendRequest(request, requestUID: requestUID)
187194

188195
do {
@@ -196,7 +203,7 @@ public extension Server {
196203
}
197204

198205
// PUTs
199-
func put<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
206+
func put<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
200207
if self.blockAllAPIsNotSupported {
201208
try self._checkAPIsContainAPI(api)
202209

@@ -216,7 +223,7 @@ public extension Server {
216223
throw ServerAPIError.taskCancelled(error: error)
217224
}
218225

219-
let request = try api.request(.PUT, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
226+
let request = try api.request(.PUT, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
220227
let decoded: T = try await self.sendRequest(request, requestUID: requestUID, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
221228

222229
do {
@@ -229,7 +236,7 @@ public extension Server {
229236
return decoded
230237
}
231238

232-
func put(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
239+
func put(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
233240
if self.blockAllAPIsNotSupported {
234241
try self._checkAPIsContainAPI(api)
235242
}
@@ -247,7 +254,7 @@ public extension Server {
247254
throw ServerAPIError.taskCancelled(error: error)
248255
}
249256

250-
let request = try api.request(.PUT, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
257+
let request = try api.request(.PUT, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
251258
let wasSuccessful = try await self.sendRequest(request, requestUID: requestUID)
252259

253260
do {
@@ -261,7 +268,7 @@ public extension Server {
261268
}
262269

263270
// DELETEs
264-
func delete<T: Codable>(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
271+
func delete<T: Codable>(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
265272
if self.blockAllAPIsNotSupported {
266273
try self._checkAPIsContainAPI(api)
267274

@@ -280,7 +287,7 @@ public extension Server {
280287
throw ServerAPIError.taskCancelled(error: error)
281288
}
282289

283-
let request = try api.request(.DELETE, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
290+
let request = try api.request(.DELETE, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
284291
let decoded: T = try await self.sendRequest(request, requestUID: requestUID, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
285292

286293
do {
@@ -293,7 +300,7 @@ public extension Server {
293300
return decoded
294301
}
295302

296-
func delete(_ api: any ServerAPI, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
303+
func delete(_ api: any ServerAPI, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
297304
if self.blockAllAPIsNotSupported {
298305
try self._checkAPIsContainAPI(api)
299306
}
@@ -309,8 +316,8 @@ public extension Server {
309316
self.logger.error("\(Date()) - (\(requestUID)) Request to \(String(describing: api.path)) [Cancelled]")
310317
throw ServerAPIError.taskCancelled(error: error)
311318
}
312-
313-
let request = try api.request(.DELETE, in: self.currentEnvironment, additionalHeaders: self.additionalHTTPHeaders, additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
319+
320+
let request = try api.request(.DELETE, in: self.currentEnvironment, additionalHeaders: self._combineAdditionalHeaders(additionalHeaders), additionalQueries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval)
314321
let wasSuccessful = try await self.sendRequest(request, requestUID: requestUID)
315322

316323
do {
@@ -392,6 +399,14 @@ public extension Server {
392399
throw ServerAPIError.badRequest(description: NSLocalizedString("API doesn't support type: `\(T.self)`.", comment: ""))
393400
}
394401
}
402+
403+
private func _combineAdditionalHeaders(_ additionalHeaders: [String: String]?) -> [String: String]? {
404+
guard let additionalHeaders else {
405+
return self.additionalHTTPHeaders
406+
}
407+
408+
return self.additionalHTTPHeaders?.merging(additionalHeaders, uniquingKeysWith: { $1 })
409+
}
395410
}
396411

397412
extension Server {

0 commit comments

Comments
 (0)