Skip to content

Commit ba414a3

Browse files
authored
Merging to master (#251)
- Cleanup (#248) - Hardcoded path to .swiftformat config file for Amplify targets - Moved MockModels to AmplifyTestCommon - Fixed AWSPluginsCoreTests - Convert Amplify.API to protocol (#249) - Separated Amplify.API into APICategory protocol and AmplifyAPICategory implementation; fixed API client behavior conformances that used to be implemented only on the API category class but not declared in the Client Behavior protocol - Refactored "Resettable" behaviors for all categories
1 parent 2bf59a4 commit ba414a3

File tree

37 files changed

+531
-347
lines changed

37 files changed

+531
-347
lines changed

Amplify.xcodeproj/project.pbxproj

Lines changed: 77 additions & 37 deletions
Large diffs are not rendered by default.

Amplify/Amplify.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class Amplify {
2626
// It is not supported to mutate these category properties. They are `var` to support the `reset()` method for
2727
// ease of testing.
2828
public static internal(set) var Analytics = AnalyticsCategory()
29-
public static internal(set) var API = APICategory()
29+
public static internal(set) var API: APICategory = AmplifyAPICategory()
3030
public static internal(set) var DataStore = DataStoreCategory()
3131
public static internal(set) var Hub = HubCategory()
3232
public static internal(set) var Logging = LoggingCategory()

Amplify/Categories/API/APICategory.swift

Lines changed: 3 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8-
/// The API category provides a solution for making HTTP requests to REST and GraphQL endpoints.
9-
final public class APICategory: Category {
10-
public let categoryType = CategoryType.api
11-
12-
var plugins = [PluginKey: APICategoryPlugin]()
13-
14-
/// Returns the plugin added to the category, if only one plugin is added. Accessing this property if no plugins
15-
/// are added, or if more than one plugin is added, will cause a preconditionFailure.
16-
var plugin: APICategoryPlugin {
17-
guard isConfigured else {
18-
preconditionFailure(
19-
"""
20-
\(categoryType.displayName) category is not configured. Call Amplify.configure() before using \
21-
any methods on the category.
22-
"""
23-
)
24-
}
25-
26-
guard !plugins.isEmpty else {
27-
preconditionFailure("No plugins added to \(categoryType.displayName) category.")
28-
}
29-
30-
guard plugins.count == 1 else {
31-
preconditionFailure(
32-
"""
33-
More than 1 plugin added to \(categoryType.displayName) category. \
34-
You must invoke operations on this category by getting the plugin you want, as in:
35-
#"Amplify.\(categoryType.displayName).getPlugin(for: "ThePluginKey").foo()
36-
"""
37-
)
38-
}
39-
40-
return plugins.first!.value
41-
}
42-
43-
var isConfigured = false
44-
45-
// MARK: - Plugin handling
46-
47-
/// Adds `plugin` to the list of Plugins that implement functionality for this category.
48-
///
49-
/// - Parameter plugin: The Plugin to add
50-
public func add(plugin: APICategoryPlugin) throws {
51-
let key = plugin.key
52-
guard !key.isEmpty else {
53-
let pluginDescription = String(describing: plugin)
54-
let error = APIError.invalidConfiguration("Plugin \(pluginDescription) has an empty `key`.",
55-
"Set the `key` property for \(String(describing: plugin))")
56-
throw error
57-
}
58-
59-
plugins[plugin.key] = plugin
60-
}
61-
62-
/// Returns the added plugin with the specified `key` property.
63-
///
64-
/// - Parameter key: The PluginKey (String) of the plugin to retrieve
65-
/// - Returns: The wrapped plugin
66-
public func getPlugin(for key: PluginKey) throws -> APICategoryPlugin {
67-
guard let plugin = plugins[key] else {
68-
let keys = plugins.keys.joined(separator: ", ")
69-
let error = APIError.invalidConfiguration("No plugin has been added for '\(key)'.",
70-
"Either add a plugin for '\(key)', or use one of the known keys: \(keys)")
71-
throw error
72-
}
73-
return plugin
74-
}
75-
76-
/// Removes the plugin registered for `key` from the list of Plugins that implement functionality for this category.
77-
/// If no plugin has been added for `key`, no action is taken, making this method safe to call multiple times.
78-
///
79-
/// - Parameter key: The key used to `add` the plugin
80-
public func removePlugin(for key: PluginKey) {
81-
plugins.removeValue(forKey: key)
82-
}
83-
8+
public protocol APICategory: Category, APICategoryClientBehavior {
9+
func add(plugin: APICategoryPlugin) throws
10+
func getPlugin(for key: PluginKey) throws -> APICategoryPlugin
8411
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// Copyright 2018-2019 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
extension AmplifyAPICategory: APICategory {
9+
10+
/// Adds `plugin` to the list of Plugins that implement functionality for this category.
11+
///
12+
/// - Parameter plugin: The Plugin to add
13+
public func add(plugin: APICategoryPlugin) throws {
14+
let key = plugin.key
15+
guard !key.isEmpty else {
16+
let pluginDescription = String(describing: plugin)
17+
let error = APIError.invalidConfiguration("Plugin \(pluginDescription) has an empty `key`.",
18+
"Set the `key` property for \(String(describing: plugin))")
19+
throw error
20+
}
21+
22+
plugins[plugin.key] = plugin
23+
}
24+
25+
/// Returns the added plugin with the specified `key` property.
26+
///
27+
/// - Parameter key: The PluginKey (String) of the plugin to retrieve
28+
/// - Returns: The wrapped plugin
29+
public func getPlugin(for key: PluginKey) throws -> APICategoryPlugin {
30+
guard let plugin = plugins[key] else {
31+
let keys = plugins.keys.joined(separator: ", ")
32+
let error = APIError.invalidConfiguration("No plugin has been added for '\(key)'.",
33+
"Either add a plugin for '\(key)', or use one of the known keys: \(keys)")
34+
throw error
35+
}
36+
return plugin
37+
}
38+
39+
/// Removes the plugin registered for `key` from the list of Plugins that implement functionality for this category.
40+
/// If no plugin has been added for `key`, no action is taken, making this method safe to call multiple times.
41+
///
42+
/// - Parameter key: The key used to `add` the plugin
43+
public func removePlugin(for key: PluginKey) {
44+
plugins.removeValue(forKey: key)
45+
}
46+
47+
}
48+
49+
extension AmplifyAPICategory: CategoryTypeable {
50+
public var categoryType: CategoryType {
51+
.api
52+
}
53+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// Copyright 2018-2019 Amazon.com,
3+
// Inc. or its affiliates. All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
/// The API category provides a solution for making HTTP requests to REST and GraphQL endpoints.
9+
final public class AmplifyAPICategory {
10+
11+
var plugins = [PluginKey: APICategoryPlugin]()
12+
13+
/// Returns the plugin added to the category, if only one plugin is added. Accessing this property if no plugins
14+
/// are added, or if more than one plugin is added, will cause a preconditionFailure.
15+
var plugin: APICategoryPlugin {
16+
guard isConfigured else {
17+
preconditionFailure(
18+
"""
19+
\(categoryType.displayName) category is not configured. Call Amplify.configure() before using \
20+
any methods on the category.
21+
"""
22+
)
23+
}
24+
25+
guard !plugins.isEmpty else {
26+
preconditionFailure("No plugins added to \(categoryType.displayName) category.")
27+
}
28+
29+
guard plugins.count == 1 else {
30+
preconditionFailure(
31+
"""
32+
More than 1 plugin added to \(categoryType.displayName) category. \
33+
You must invoke operations on this category by getting the plugin you want, as in:
34+
#"Amplify.\(categoryType.displayName).getPlugin(for: "ThePluginKey").foo()
35+
"""
36+
)
37+
}
38+
39+
return plugins.first!.value
40+
}
41+
42+
/// `true` if this category has been configured with `Amplify.configure()`.
43+
///
44+
/// - Warning: This property is intended for use by plugin developers.
45+
public var isConfigured = false
46+
47+
}

Amplify/Categories/API/ClientBehavior/APICategoryGraphQLBehavior.swift

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
/// Behavior of the API category related to GraphQL operations
99
public protocol APICategoryGraphQLBehavior: class {
1010

11+
// MARK: - Model-based GraphQL Operations
12+
1113
/// Perform a GraphQL query for a single `Model` item. This operation will be asychronous, with the callback
1214
/// accessible both locally and via the Hub.
1315
///
@@ -44,18 +46,6 @@ public protocol APICategoryGraphQLBehavior: class {
4446
type: GraphQLMutationType,
4547
listener: GraphQLOperation<M>.EventListener?) -> GraphQLOperation<M>
4648

47-
/// Performs a GraphQL mutate for the `AnyModel` item. This operation will be asynchronous, with the callback
48-
/// accessible both locally and via the Hub.
49-
///
50-
/// - Parameters:
51-
/// - model: The instance of the `AnyModel`.
52-
/// - type: The type of mutation to apply on the instance of `AnyModel`.
53-
/// - listener: The event listener for the operation
54-
/// - Returns: The AmplifyOperation being enqueued.
55-
func mutate(ofAnyModel anyModel: AnyModel,
56-
type: GraphQLMutationType,
57-
listener: GraphQLOperation<AnyModel>.EventListener?) -> GraphQLOperation<AnyModel>
58-
5949
/// Performs a GraphQL subscribe operation for `Model` items.
6050
///
6151
/// - Parameters:
@@ -68,6 +58,8 @@ public protocol APICategoryGraphQLBehavior: class {
6858
listener: GraphQLSubscriptionOperation<M>.EventListener?)
6959
-> GraphQLSubscriptionOperation<M>
7060

61+
// MARK: - Request-based GraphQL Operations
62+
7163
/// Perform a GraphQL query operation against a previously configured API. This operation
7264
/// will be asynchronous, with the callback accessible both locally and via the Hub.
7365
///
@@ -99,6 +91,20 @@ public protocol APICategoryGraphQLBehavior: class {
9991
listener: GraphQLSubscriptionOperation<R>.EventListener?)
10092
-> GraphQLSubscriptionOperation<R>
10193

94+
// MARK: - GraphQL operations without a specified type
95+
96+
/// Performs a GraphQL mutate for the `AnyModel` item. This operation will be asynchronous, with the callback
97+
/// accessible both locally and via the Hub.
98+
///
99+
/// - Parameters:
100+
/// - model: The instance of the `AnyModel`.
101+
/// - type: The type of mutation to apply on the instance of `AnyModel`.
102+
/// - listener: The event listener for the operation
103+
/// - Returns: The AmplifyOperation being enqueued.
104+
func mutate(ofAnyModel anyModel: AnyModel,
105+
type: GraphQLMutationType,
106+
listener: GraphQLOperation<AnyModel>.EventListener?) -> GraphQLOperation<AnyModel>
107+
102108
/// An internal method used by Plugins to perform initial subscriptions on registered model types to keep them in
103109
/// sync with DataStore.
104110
///

Amplify/Categories/API/ClientBehavior/APICategory+GraphQLBehavior.swift renamed to Amplify/Categories/API/ClientBehavior/AmplifyAPICategory+GraphQLBehavior.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8-
extension APICategory: APICategoryGraphQLBehavior {
8+
extension AmplifyAPICategory: APICategoryGraphQLBehavior {
9+
10+
// MARK: - Model-based GraphQL Operations
911

1012
public func query<M: Model>(from modelType: M.Type,
1113
byId id: String,
@@ -25,19 +27,15 @@ extension APICategory: APICategoryGraphQLBehavior {
2527
plugin.mutate(of: model, type: type, listener: listener)
2628
}
2729

28-
public func mutate(ofAnyModel anyModel: AnyModel,
29-
type: GraphQLMutationType,
30-
listener: GraphQLOperation<AnyModel>.EventListener?) -> GraphQLOperation<AnyModel> {
31-
plugin.mutate(ofAnyModel: anyModel, type: type, listener: listener)
32-
}
33-
3430
public func subscribe<M: Model>(from modelType: M.Type,
3531
type: GraphQLSubscriptionType,
3632
listener: GraphQLSubscriptionOperation<M>.EventListener?)
3733
-> GraphQLSubscriptionOperation<M> {
3834
plugin.subscribe(from: modelType, type: type, listener: listener)
3935
}
4036

37+
// MARK: - Request-based GraphQL operations
38+
4139
public func query<R: Decodable>(request: GraphQLRequest<R>,
4240
listener: GraphQLOperation<R>.EventListener?) -> GraphQLOperation<R> {
4341
plugin.query(request: request, listener: listener)
@@ -54,6 +52,14 @@ extension APICategory: APICategoryGraphQLBehavior {
5452
plugin.subscribe(request: request, listener: listener)
5553
}
5654

55+
// MARK: - GraphQL operations without a specified type
56+
57+
public func mutate(ofAnyModel anyModel: AnyModel,
58+
type: GraphQLMutationType,
59+
listener: GraphQLOperation<AnyModel>.EventListener?) -> GraphQLOperation<AnyModel> {
60+
plugin.mutate(ofAnyModel: anyModel, type: type, listener: listener)
61+
}
62+
5763
public func subscribe(toAnyModelType modelType: Model.Type,
5864
subscriptionType: GraphQLSubscriptionType,
5965
listener: GraphQLSubscriptionOperation<AnyModel>.EventListener?)

Amplify/Categories/API/ClientBehavior/APICategory+InterceptorBehavior.swift renamed to Amplify/Categories/API/ClientBehavior/AmplifyAPICategory+InterceptorBehavior.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8-
extension APICategory: APICategoryInterceptorBehavior {
8+
extension AmplifyAPICategory: APICategoryInterceptorBehavior {
99

1010
public func add(interceptor: URLRequestInterceptor, for apiName: String) throws {
1111
try plugin.add(interceptor: interceptor, for: apiName)

Amplify/Categories/API/ClientBehavior/APICategory+RESTBehavior.swift renamed to Amplify/Categories/API/ClientBehavior/AmplifyAPICategory+RESTBehavior.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import Foundation
99

10-
extension APICategory: APICategoryRESTBehavior {
10+
extension AmplifyAPICategory: APICategoryRESTBehavior {
1111
public func get(request: RESTRequest, listener: RESTOperation.EventListener?) -> RESTOperation {
1212
plugin.get(request: request, listener: listener)
1313
}

Amplify/Categories/API/Internal/APICategory+CategoryConfigurable.swift

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0
66
//
77

8-
import Foundation
9-
10-
extension APICategory: CategoryConfigurable {
8+
extension AmplifyAPICategory: CategoryConfigurable {
119

1210
func configure(using configuration: CategoryConfiguration) throws {
1311
guard !isConfigured else {
@@ -33,20 +31,4 @@ extension APICategory: CategoryConfigurable {
3331
try configure(using: configuration)
3432
}
3533

36-
func reset(onComplete: @escaping BasicClosure) {
37-
let group = DispatchGroup()
38-
39-
for plugin in plugins.values {
40-
group.enter()
41-
plugin.reset { group.leave() }
42-
}
43-
44-
ModelRegistry.reset()
45-
46-
group.wait()
47-
48-
isConfigured = false
49-
onComplete()
50-
}
51-
5234
}

0 commit comments

Comments
 (0)