-
-
Notifications
You must be signed in to change notification settings - Fork 113
Networking 3 Transition Guide
Hi, and welcome to the third major release of Networking. Jumping from 0.x.x to 1.0.0 was a matter of how mature the project was, before jumping to 1.0.0 the library was tested in 3 big production apps, received a lot of feedback from the developers and was ready to receive input from the world. Among other things, the jump to 1.0.0 brought a lot of attention, especially from iOSDevWeekly and CocoaControls.
The jump to 2.0.0 was mainly the conversion of the whole codebase to Swift 3. The jump was easy, mainly since a lot of the core APIs were left as untouched as possible to ease the jump to Swift 3, this of course meant that some parts of Networking didn't feel very swifty. After 3 months of 2.0.0 we have refined Networking, refactored the internals, improved the unit tests and now we're ready to delete all the deprecated methods and make the big jump to 3.0.0.
Things that you need to change in order to use Networking 3.
We have changed the authentication methods to be easier to understand and to increase readability.
// Networking 2
networking.authenticate(username: "user", password: "passwd")
// Networking 3
networking.setAuthorizationHeader(username: "user", password: "passwd")
// Networking 2
networking.authenticate(token: "hi-mom")
// Networking 3
networking.setAuthorizationHeader(token: "hi-mom")
// Networking 2
networking.authenticate(headerValue: "hi-mom")
// Networking 3
networking.setAuthorizationHeader(headerValue: "hi-mom")
// Networking 2
networking.authenticate(headerKey: "Anonymous-Token", headerValue: "hi-mom")
// Networking 3
networking.setAuthorizationHeader(headerKey: "Anonymous-Token", headerValue: "hi-mom")
The Swift API naming guidelines state that the methods should be lowercase.
// Networking 2
networking.GET(...) { ...
networking.POST(...) { ..
networking.PUT(...) { ...
networking.DELETE(...) { ...
// Networking 3
networking.get(...) { ...
networking.post(...) { ..
networking.put(...) { ...
networking.delete(...) { ...
A few methods that were asynchronous, weren't really meant to be async, having them like that actually made things a bit more complex and cumbersome, so we converted them to sync calls.
// Networking 2
networking.imageFromCache("/imagepath") { image in
//...
}
// Networking 3
let image = networking.imageFromCache()
// Networking 2
networking.dataFromCache("/videopath") { data in
//...
}
// Networking 3
let data = networking.dataFromCache("/videopath")
// Networking 2
networking.cancelAllRequests {
// Finished cancelling all requests
}
// Networking 3
networking.cancelAllRequests()
// Networking 2
networking.cancelGET("/get") {
// Finished cancelling GET "/get" requests
}
// Networking 3
networking.cancelGET("/get")
// Networking 2
networking.cancelPOST("/post") {
// Finished cancelling GET "/post" requests
}
// Networking 3
networking.cancelPOST("/post")
// Networking 2
networking.cancelPUT("/put") {
// Finished cancelling PUT "/put" requests
}
// Networking 3
networking.cancelPUT("/put")
// Networking 2
networking.cancelDELETE("/delete") {
// Finished cancelling DELETE "/delete" requests
}
// Networking 3
networking.cancelDELETE("/delete")
If you aren't familiar with the Result type, is what most networking libraries are using these days to deal with the awful amount of optional and unwrappings that we have to deal when doing networking. Before the Result type we had this problem:
// The old way
let networking = Networking(baseURL: "http://httpbin.org")
networking.get("/get") { json, headers, error in // Both are optional
if let error = error {
// OK, now we can handle the error
} else if let jsonArray = json as? [[String: Any]] {
// A valid JSON! Yay!
} else {
// Oh god, this shouldn't be happening, what do we do?!
}
}
Now, we don't have to do it like that, leveraging in the Result type fixes this problem, the Result type is an enum that has two cases: success
and failure
. The success
case has a response, the failure
case has an error and a response, none of these ones are optionals, no more unwrapping!
Here's how to use it:
// The best way
let networking = Networking(baseURL: "http://fakerecipes.com")
networking.get("/recipes") { result in
switch result {
case .success(let response):
// We know we'll be receiving an array with the best recipes, so we can just do:
let recipes = response.arrayBody // BOOM, no optionals. [[String: Any]]
// If we need headers or response status code we can use the HTTPURLResponse for this.
let headers = response.headers // [String: Any]
case .failure(let response):
// Non-optional error ✨
let errorCode = response.error.code
// Our backend developer told us that they will send a json with some
// additional information on why the request failed, this will be a dictionary.
let json = response.dictionaryBody // BOOM, no optionals here [String: Any]
// We want to know the headers of the failed response.
let headers = response.headers // [String: Any]
}
}
And that's how we do things in Networking without optionals.