Skip to content

Commit f095eb6

Browse files
committed
Add helper methods onto server that lookup the api based on the path and other specified information.
1 parent 39181ff commit f095eb6

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

Sources/ComposableArchitecturePattern/Server.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ public extension Server {
139139
return decoded
140140
}
141141

142+
/// Sends a GET request and returns the specified value type based on the specified path.
143+
///
144+
/// The default implementation attempts to find and unwrap the first api that supports `path`, `GET` http method, `currentEnvironment` (if the API's environment is specified), and supports the return type. If none are found, it throws a `ServerAPIError.badRequest`. If an api is found, it gets unwrapped and then this calls `-get(using:, to:, additionalHeaders:, queries:, httpBodyOverride:, timeoutInterval:, dataDecodingStrategry:, keyDecodingStrategy:)`.
145+
///
146+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
147+
/// - 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.
148+
func get<T: Decodable>(path: String, endpoint: String?, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy?) async throws -> T {
149+
guard let api = self.apis.first(where: { $0.path == path && $0.supportedHTTPMethods.contains(.GET) && ($0.environment != nil ? $0.environment == self.currentEnvironment : true) && $0.supports(T.self) }) else {
150+
throw ServerAPIError.notImplemented(description: "No API found for \(path)")
151+
}
152+
153+
return try await self.get(using: api, to: endpoint, additionalHeaders: additionalHeaders, queries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
154+
}
155+
142156
// POSTs
143157
func post<T: Decodable>(using api: any ServerAPI, to endpoint: String? = nil, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? = nil, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy? = nil) async throws -> T {
144158
if self.blockAllAPIsNotSupported {
@@ -202,6 +216,20 @@ public extension Server {
202216
return wasSuccessful
203217
}
204218

219+
/// Sends a POST request and returns the specified value type based on the specified path.
220+
///
221+
/// The default implementation attempts to find and unwrap the first api that supports `path`, `POST` http method, `currentEnvironment` (if the API's environment is specified), and supports the return type. If none are found, it throws a `ServerAPIError.badRequest`. If an api is found, it gets unwrapped and then this calls `-post(using:, to:, additionalHeaders:, queries:, httpBodyOverride:, timeoutInterval:, dataDecodingStrategry:, keyDecodingStrategy:)`.
222+
///
223+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
224+
/// - 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.
225+
func post<T: Decodable>(path: String, endpoint: String?, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy?) async throws -> T {
226+
guard let api = self.apis.first(where: { $0.path == path && $0.supportedHTTPMethods.contains(.POST) && ($0.environment != nil ? $0.environment == self.currentEnvironment : true) && $0.supports(T.self) }) else {
227+
throw ServerAPIError.notImplemented(description: "No API found for \(path)")
228+
}
229+
230+
return try await self.post(using: api, to: endpoint, additionalHeaders: additionalHeaders, queries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
231+
}
232+
205233
// PUTs
206234
func put<T: Decodable>(using api: any ServerAPI, to endpoint: String? = nil, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? = nil, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy? = nil) async throws -> T {
207235
if self.blockAllAPIsNotSupported {
@@ -267,6 +295,20 @@ public extension Server {
267295
return wasSuccessful
268296
}
269297

298+
/// Sends a PUT request and returns the specified value type based on the specified path.
299+
///
300+
/// The default implementation attempts to find and unwrap the first api that supports `path`, `PUT` http method, `currentEnvironment` (if the API's environment is specified), and supports the return type. If none are found, it throws a `ServerAPIError.badRequest`. If an api is found, it gets unwrapped and then this calls `-put(using:, to:, additionalHeaders:, queries:, httpBodyOverride:, timeoutInterval:, dataDecodingStrategry:, keyDecodingStrategy:)`.
301+
///
302+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
303+
/// - 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.
304+
func put<T: Decodable>(path: String, endpoint: String?, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy?) async throws -> T {
305+
guard let api = self.apis.first(where: { $0.path == path && $0.supportedHTTPMethods.contains(.PUT) && ($0.environment != nil ? $0.environment == self.currentEnvironment : true) && $0.supports(T.self) }) else {
306+
throw ServerAPIError.notImplemented(description: "No API found for \(path)")
307+
}
308+
309+
return try await self.put(using: api, to: endpoint, additionalHeaders: additionalHeaders, queries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
310+
}
311+
270312
// DELETEs
271313
func delete<T: Decodable>(using api: any ServerAPI, to endpoint: String? = nil, additionalHeaders: [String: String]? = nil, queries: [URLQueryItem]? = nil, httpBodyOverride httpBody: Data? = nil, timeoutInterval: TimeInterval? = nil, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? = nil, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy? = nil) async throws -> T {
272314
if self.blockAllAPIsNotSupported {
@@ -330,6 +372,20 @@ public extension Server {
330372
return wasSuccessful
331373
}
332374

375+
/// Sends a DELETE request and returns the specified value type based on the specified path.
376+
///
377+
/// The default implementation attempts to find and unwrap the first api that supports `path`, `DELETE` http method, `currentEnvironment` (if the API's environment is specified), and supports the return type. If none are found, it throws a `ServerAPIError.badRequest`. If an api is found, it gets unwrapped and then this calls `-delete(using:, to:, additionalHeaders:, queries:, httpBodyOverride:, timeoutInterval:, dataDecodingStrategry:, keyDecodingStrategy:)`.
378+
///
379+
/// - Note: `additionalHeaders` will override a key-value in `additionalHTTPHeaders`.
380+
/// - 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.
381+
func delete<T: Decodable>(path: String, endpoint: String?, additionalHeaders: [String: String]?, queries: [URLQueryItem]?, httpBodyOverride httpBody: Data?, timeoutInterval: TimeInterval?, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy?, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy?) async throws -> T {
382+
guard let api = self.apis.first(where: { $0.path == path && $0.supportedHTTPMethods.contains(.DELETE) && ($0.environment != nil ? $0.environment == self.currentEnvironment : true) && $0.supports(T.self) }) else {
383+
throw ServerAPIError.notImplemented(description: "No API found for \(path)")
384+
}
385+
386+
return try await self.delete(using: api, to: endpoint, additionalHeaders: additionalHeaders, queries: queries, httpBodyOverride: httpBody, timeoutInterval: timeoutInterval, dateDecodingStrategy: dateDecodingStrategy, keyDecodingStrategy: keyDecodingStrategy)
387+
}
388+
333389
func sendRequest<T: Decodable>(_ request: URLRequest, requestUID: UUID, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy? = nil, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy? = nil) async throws -> T {
334390
let data = try await self.courier.sendRequest(request, requestUID: requestUID)
335391

0 commit comments

Comments
 (0)