@sids7
iOS at Flipkart
"Why another networking library?"
State of the Art:
Moya
One place for all your requests
Simple & Familiar
Easy to Understand
simple, readable, declarative way of writing network requests
all request creation code in one place
your API becomes a type
your requests become functions
Demo
class Bin: WebService {
static var serverURL = "https://httpbin.org"
static var networkInterface: WebServiceNetworkInterface = Swifty()
static func getIP() -> NetworkResource {
return server.get("ip")
}
static func createUser(user: [String: String]) -> NetworkResource {
return server.post("post").json(body: user).header(key: "My", value: "Header")
}
}
This is your API ( a type)
This is a request (a function)
in Objective-C
@implementation ViewController: UIViewController {
- (void) viewDidLoad {
}
@end
in Objective-C
@implementation ViewController: UIViewController {
- (void) viewDidLoad {
[Bin getIP]
}
@end
in Objective-C
@implementation ViewController: UIViewController {
- (void) viewDidLoad {
[Bin getIP] load:^{
}];
}
@end
in Objective-C
@implementation ViewController: UIViewController {
- (void) viewDidLoad {
[Bin getIP] load:^(NSURLResponse *response, id data, NSError *error){
// Here's your response
}];
}
@end
static func getIP() -> NetworkResource {
return server.get("ip")
}
static func getIP() -> NetworkResource {
return server.get("ip")
.json("user": "name")
}
static func getIP() -> NetworkResource {
return server.get("ip")
.query("user": "name")
}
Compile Time Checks
server
.get()
.post()
.put()
.delete()
.query()
.fields()
.data()
.json()
.header()
.contentType()
.priority()
.mock()
.deliver(on:)
.tag()
.deliver(on:)
class ViewController: UIViewController {
override viewDidLoad(){
Bin.getIP().load(){ (response, data, error) in
// Here's your response
}
}
}
class DataStore {
// Should work in the background
override refreshIP(){
}
}
.deliver(on:)
class DataStore {
// Should work in the background
override refreshIP(){
let backgroundQueue = DispatchQueue("com.background.processing")
}
}
.deliver(on:)
class DataStore {
// Should work in the background
override refreshData(){
let backgroundQueue = DispatchQueue("com.background.processing")
Bin.getIP()
}
}
.deliver(on:)
class DataStore {
// Should work in the background
override refreshData(){
let backgroundQueue = DispatchQueue("com.background.processing")
Bin.getIP().deliver(on: backgroundQueue)
}
}
.deliver(on:)
class DataStore {
// Should work in the background
override refreshData(){
let backgroundQueue = DispatchQueue("com.background.processing")
Bin.getIP().deliver(on: backgroundQueue).load(){ ... }
}
}
.priority()
class Bin: WebService {
static var serverURL = "https://httpbin.org"
static var networkInterface: WebServiceNetworkInterface = Swifty()
static func getIP() -> NetworkResource {
return server.get("ip")
}
static func createUser(user: [String: String]) -> NetworkResource {
return server.post("post").json(body: user)
}
}
.priority()
class Bin: WebService {
static var serverURL = "https://httpbin.org"
static var networkInterface: WebServiceNetworkInterface = Swifty()
static func getIP() -> NetworkResource {
return server.get("ip").priority(.high)
}
static func createUser(user: [String: String]) -> NetworkResource {
return server.post("post").json(body: user)
}
}
.mock()
static func getIP() -> NetworkResource {
return server.get("ip")
}
.mock()
static func getIP() -> NetworkResource {
return server.get("ip").mock
}
.mock()
static func getIP() -> NetworkResource {
return server.get("ip").mock(file: "response.json")
}
server
.get()
.post()
.put()
.delete()
.query()
.fields()
.data()
.json()
.header()
.contentType()
.priority()
.mock()
.deliver(on:)
.tag()
Extending WebService
extension NetworkResource {
}
Encrypt Data and Set Body
Extending WebService
extension NetworkResource {
func encrypt(data: Data){
}
}
Encrypt Data and Set Body
Extending WebService
extension NetworkResource {
func encrypt(data: Data) -> NetworkResource {
}
}
Encrypt Data and Set Body
Extending WebService
extension NetworkResource {
func encrypt(data: Data) -> NetworkResource {
let encrptedData = ourSecretEncryptor(data)
}
}
Encrypt Data and Set Body
Extending WebService
extension NetworkResource {
func encrypt(data: Data) -> NetworkResource {
let encrptedData = ourSecretEncryptor(data)
self.data(encryptedData)
}
}
Encrypt Data and Set Body
Extending WebService
extension NetworkResource {
func encrypt(data: Data) -> NetworkResource {
let encrptedData = ourSecretEncryptor(data)
self.data(encryptedData)
return self
}
}
Encrypt Data and Set Body
server
.get()
.post()
.put()
.delete()
.query()
.fields()
.data()
.json()
.header()
.contentType()
.encrypt()
.priority()
.mock()
.deliver(on:)
.tag()
WebService abstracts the actual networking from the upper layers
Gives you a simple async syntax: .load()
Multiple WebServices in your app is completely Acceptable
Example: one for contacting your server, one for external servers
You still have granular control over the networking
the module that powers your .load() function
Swifty
class OAuthConstraint: Constraint {
override func isConstraintSatisfied(for resource: NetworkResource) -> Bool {
// return false if we don't have the OAuth Token
// return true if we already have the OAuth Token
}
override func satisfyConstraint(for resource: NetworkResource) {
// Get the OAuth token from the server
// Make sure to call finish() when done
finish()
}
}
class OAuthTokenAddingInterceptor: RequestInterceptor {
func intercept(resource: NetworkResource) -> NetworkResource {
// Get the token from where your Constraint
let token = Keychain.string(key: "OAuth")
// Attach it to the resource:
resource.header(key: "Token", value: token)
// Return the modified resource
return resource
}
}
class ErrorCheckingInterceptor: ResponseInterceptor {
func intercept(response: NetworkResponse) -> NetworkResponse {
if let statusCode = response.response?.statusCode, statusCode == 204 {
response.fail(error: SwiftyError.responseValidation())
}
return response
}
}
Performance Tests in the Example Project
~ 8000 downloads ⏬
58 apps 🚀
Swifty
https://github.com/Flipkart/Swifty
pod try Swifty or pod 'Swifty'