Skip to content

Commit 753b70c

Browse files
committed
Update to allow server to support any server API.
1 parent a332b79 commit 753b70c

File tree

2 files changed

+38
-20
lines changed

2 files changed

+38
-20
lines changed

Sources/ComposableArchitecturePattern/Server+API.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@ public protocol ServerAPI: Identifiable, Equatable {
2323
func supports<T: Codable>(_ object: T.Type) -> Bool
2424
}
2525

26+
extension Sequence where Element == Codable.Type {
27+
func isEqual(to other: [Codable.Type]) -> Bool {
28+
self.contains(where: { type in other.contains(where: { $0 == type }) })
29+
}
30+
}
31+
32+
extension ServerAPI {
33+
func isEqual(to api: any ServerAPI) -> Bool {
34+
let returnObjectsEquatable = {
35+
if let supportedReturnObjects, let otherSupportedReturnObjects = api.supportedReturnObjects {
36+
return supportedReturnObjects.isEqual(to: otherSupportedReturnObjects)
37+
}
38+
return true
39+
}
40+
41+
return self.environment == api.environment && self.path == api.path && self.headers == api.headers && self.queries == api.queries && self.body == api.body && self.supportedHTTPMethods == api.supportedHTTPMethods && self.timeoutInterval == api.timeoutInterval && returnObjectsEquatable()
42+
}
43+
}
44+
2645
public extension ServerAPI {
2746
subscript(httpMethod: HTTPMethod) -> URLRequest? {
2847
guard let httpMethodIndex = self.supportedHTTPMethods.firstIndex(of: httpMethod) else {

Sources/ComposableArchitecturePattern/Server.swift

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public protocol Server: Actor {
2525
/// Whether or not to log all activity wtih this server.
2626
var logActivity: LogActivity { get }
2727

28-
associatedtype API: ServerAPI
29-
var apis: [API] { get }
28+
var apis: [any ServerAPI] { get }
3029

3130
var blockAllAPIsNotSupported: Bool { get }
3231
var requestsBeingProcessed: Set<UUID> { get set }
@@ -38,23 +37,23 @@ public protocol Server: Actor {
3837
environments: [ServerEnvironment],
3938
currentEnvironment: ServerEnvironment?,
4039
additionalHTTPHeaders: [String : String]?,
41-
supportedAPIs: [API],
40+
supportedAPIs: [any ServerAPI],
4241
logActivity: LogActivity
4342
)
4443

45-
func get<T: Codable>(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
44+
func get<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
4645

47-
func post<T: Codable>(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
46+
func post<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
4847

49-
func post(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
48+
func post<A: ServerAPI>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
5049

51-
func put<T: Codable>(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
50+
func put<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
5251

53-
func put(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
52+
func put<A: ServerAPI>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
5453

55-
func delete<T: Codable>(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
54+
func delete<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> T
5655

57-
func delete(_ api: API, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
56+
func delete<A: ServerAPI>(_ api: A, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy) async throws -> Bool
5857

5958
/// Send the given request to the server and return the decoded object.
6059
/// - Returns: The given decoded type or an `APIError`.
@@ -77,7 +76,7 @@ public extension Server {
7776
}
7877

7978
// GETs
80-
func get<T: Codable>(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
79+
func get<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
8180
if self.blockAllAPIsNotSupported {
8281
try self._checkAPIsContainAPI(api)
8382

@@ -111,7 +110,7 @@ public extension Server {
111110
}
112111

113112
// POSTs
114-
func post<T: Codable>(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
113+
func post<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
115114
if self.blockAllAPIsNotSupported {
116115
try self._checkAPIsContainAPI(api)
117116

@@ -143,7 +142,7 @@ public extension Server {
143142
return decoded
144143
}
145144

146-
func post(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
145+
func post<A: ServerAPI>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
147146
if self.blockAllAPIsNotSupported {
148147
try self._checkAPIsContainAPI(api)
149148
}
@@ -174,7 +173,7 @@ public extension Server {
174173
}
175174

176175
// PUTs
177-
func put<T: Codable>(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
176+
func put<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
178177
if self.blockAllAPIsNotSupported {
179178
try self._checkAPIsContainAPI(api)
180179

@@ -207,7 +206,7 @@ public extension Server {
207206
return decoded
208207
}
209208

210-
func put(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
209+
func put<A: ServerAPI>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
211210
if self.blockAllAPIsNotSupported {
212211
try self._checkAPIsContainAPI(api)
213212
}
@@ -239,7 +238,7 @@ public extension Server {
239238
}
240239

241240
// DELETEs
242-
func delete<T: Codable>(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
241+
func delete<A: ServerAPI, T: Codable>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
243242
if self.blockAllAPIsNotSupported {
244243
try self._checkAPIsContainAPI(api)
245244

@@ -271,7 +270,7 @@ public extension Server {
271270
return decoded
272271
}
273272

274-
func delete(_ api: API, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
273+
func delete<A: ServerAPI>(_ api: A, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> Bool {
275274
if self.blockAllAPIsNotSupported {
276275
try self._checkAPIsContainAPI(api)
277276
}
@@ -359,13 +358,13 @@ public extension Server {
359358
/// Checks if the `apis` contains the given api.
360359
///
361360
/// - Throws: A `ServerAPIError` if not found.
362-
fileprivate func _checkAPIsContainAPI(_ api: API) throws {
363-
guard self.apis.contains(api) else {
361+
fileprivate func _checkAPIsContainAPI(_ api: any ServerAPI) throws {
362+
guard self.apis.contains(where: { $0.isEqual(to: api) }) else {
364363
throw ServerAPIError.badRequest(description: NSLocalizedString("API for path \(api.path) isn't supported.", comment: ""))
365364
}
366365
}
367366

368-
fileprivate func _checkAPISupportsType<T: Codable>(_ api: API, type: T.Type) throws {
367+
fileprivate func _checkAPISupportsType<T: Codable>(_ api: any ServerAPI, type: T.Type) throws {
369368
guard api.supports(T.self) else {
370369
throw ServerAPIError.badRequest(description: NSLocalizedString("API doesn't support type: `\(T.self)`.", comment: ""))
371370
}

0 commit comments

Comments
 (0)