The General Connection Framework (GCF) is part of mobileforming's modularization effort. GCF will allow you to spend less time writing boilerplate networking code, less time dealing with the nitty gritty, sometimes complex code surrounding authentication and retry logic, and more time making your apps awesome. With every new app, you'll be able to reuse existing GCF code as well as create custom plugins specific to your API needs. Every project utilizing the GCF will have an increased level of confidence in the network code, in addition to other shared benefits.
- Never have to write URLSession code in your app again (cuts down on network code)
- No more JSON parsing
- Will be fully tested (no buggy network code)
- Easier/quicker API integration
- Less fragile (no string literal parameters for creating a request)
- Supports standard completion block pattern or Rx/observable pattern
- Encourages modular design
- Bain says so...
- Modular
- Highly configurable
- Flexible plugin architecture
- Swift Decodable support
- Robust test coverage (ongoing)
- Request queueing
- Authentication support
- Credential management
- Retry logic
- iOS 9.0+
- Xcode 9
- Swift 4
- CocoaPods
- Add the correct podspec source url to the project's podfile
- This will either be the internal mobileforming spec repo or a client specific spec repo
- Also add the master spec repo source url since this will no longer be implicitly added
- Specify the correct GCF version for the target(s) in the podfile.
- pod 'GenericConnectionFramework', '~> 1.0'
- Add the correct nexus credentials to the computer if you're using the static framework
- Must get these from Techops
- in terminal: echo "machine nexus.mobileforming.com login {username} password {password}" >> ~/.netrc
- Run pod install (may need to run pod update first)
- Open the workspace, clean, and build
See playground for more detailed explanation and examples
public protocol Routable {
var path: String { get }
var method: HTTPMethod { get }
var headers: [String : String]? { get }
var parameters: [String : String]? { get }
var body: [String : AnyHashable]? { get }
var defaultTimeout: TimeInterval { get }
var cachePolicy: URLRequest.CachePolicy { get }
}
protocol GCF: class {
var baseURL: String { get }
var urlSession: URLSession { get }
var decoder: JSONDecoder { get }
var plugin: GCFPlugin? { get }
init(baseURL: String, decoder: JSONDecoder)
func sendRequest<T: Codable>(for routable: Routable) -> Observable<T>
func sendRequest<T: Codable>(for routable: Routable, completion: @escaping (T?, Error?) -> Void)
func sendRequest(for routable: Routable, completion: @escaping (Bool, Error?) -> Void)
func constructURL(from routable: Routable) -> URL
func parseData<T: Codable>(from data: Data) throws -> T
func configurePlugin(_ plugin: GCFPlugin)
func configurePlugins(_ plugins: [GCFPlugin])
}
//Plugin interface
protocol GCFPlugin {
func willSendRequest(_ request: inout URLRequest)
func didReceive(data: Data?, response: URLResponse?, error: Error?, forRequest request: inout URLRequest) throws
}
//1. create an instance of the GCF
let gcf = RxGCF(baseURL: "https://somebaseurl.com")
//or you can optionally provide an instance of JSONDecoder for GCF to use (allows you to configure the data or date format)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let gcf = RxGCF(baseURL: "https://somebaseurl.com", decoder: decoder)
//2. Configure plugin
gcf.configurePlugin(plugin)
//or you can optionally apply any plugins (1 or more) to this gcf instance.
//GCF will process the plugins in order for willSend, and reverse order for didReceive
gcf.configurePlugins([plugin1, plugin2, plugin3])
//3. use with completion, LoginObject: Codable
gcf.sendRequest(for: ExampleAPI.login) { (response: LoginObject?, error) in
}
//or use as observable, LoginObject: Decodable
let loginObservable: Observable<LoginObject> = gcf.sendRequest(for: ExampleAPI.login)