Nothing but net(working).
Swish is a networking library that is particularly meant for requesting and decoding JSON via Argo. It is protocol based, and so aims to be easy to test and customize.
Add the following to your Cartfile:
github "thoughtbot/Swish"
Then run carthage update
.
Follow the current instructions in Carthage's README for up to date installation instructions.
import Swish
func baseRequest(url url: String, method: RequestMethod) -> NSURLRequest {
let url = NSURL(string: url)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = method.rawValue
return request
}
struct CommentRequest: Request {
typealias ResponseObject = Comment
let id: Int
func build() -> NSURLRequest {
let endpoint = "http://example.com/api/comment/\(id)"
return baseRequest(endpoint: endpoint, method: .GET)
}
}
struct Comment: Decodable {
let id: Int
let text: String
let username: String
static func decode(j: JSON) -> Decoded<Comment> {
return curry(Comment.init)
<^> j <| "id"
<*> j <| "commentText"
<*> j <| "username"
}
}
let request = CommentRequest(id: 1)
APIClient().performRequest(request) { (response: Result<Comment, NSError>) in
// ...
}
We declare a struct that conforms to the Request
protocol, which forces us to:
- Declare a
ResponseObject
that should beDecodable
, which allows Swish to use Argo to decode the HTTP response into the appropriate model. - Declare a
build
function, which defines the request to perform. HTTP method to use.
Then, we can use APIClient#performRequest
to actually perform the request, and
its callback will have an argument of type Result<ResponseObject, NSError>
.
One can additionally override the default implementation of both
APIClient#performRequest
and Request#parse
to provide more custom behavior.
The default APIClient#performRequest
does the following:
- Check that the HTTP Status Code is between
200...299
, else return anNSError
. - Parse the response's data into
Argo.JSON
- Pass this
JSON
to theRequest#parse
function.
The default Request#parse
just passes the JSON
it is called with to the
ResponseObject.decode
function.
As an example of a custom parse
function, let's assume that in the example
above, the API returns an array of objects, and we want to parse only the first
one into a Comment
, or otherwise fail:
struct CommentRequest: Request {
typealias ResponseObject = Comment
let id: Int
func build() -> NSURLRequest {
let endpoint = "http://example.com/api/comment/\(id)"
return baseRequest(endpoint: endpoint, method: .GET)
}
func parse(j: JSON) -> Result<Comment, NSError> {
let comments = [Comment].decode(j)
let comment = comments.flatmap { comments -> Decoded<Comment> in
guard let comment = comments.first else {
return .Failure(.Custom("No comments returned!"))
}
return .Success(comment)
}
return .fromDecoded(comment)
}
}
Here, our parse function will first decode into an array of Comment
objects,
and then return the first if found, otherwise an error. The fromDecoded
function converts from Argo's Decoded<T>
type to Result<T, NSError>
.
Swish is Copyright (c) 2015 thoughtbot, inc. It is free software, and may be redistributed under the terms specified in the LICENSE file.
Swish is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.
We love open source software! See our other projects or look at our product case studies and hire us to help build your iOS app.