ReactiveJSON is a Swift network framework for JSON services, built using ReactiveCocoa. The framework is minimally designed, yet still highly flexibile.
Features includes:
- Easy-to-create, and highly adatable JSON clients;
- Support for the most common HTTP methods;
- Parameter encoding;
- OAuth2 token support;
- Automatic JSON parsing;
After a tiny bit of setup, requests look like this:
// Create a `SignalProducer` that will execute the network request when started.
MyJSONService
.request(endpoint: "foo")
.startWithResult {
// `value` is inferred to be `Any`
print($0.value)
}
//------------------------------------------------------------------------------
// Bind a GET request to a `MutableProperty`
let users = MutableProperty<[[String:AnyObject]]>([])
users <~ MyJSONService
.request(endpoint: "users")
.ignoreError()
//------------------------------------------------------------------------------
// Send a POST request
MyJSONService
.request(endpoint: "sprocket", method: .Post, parameters: ["foo":"bar"])
.startWithCompleted {
print("huzzah!")
}
Here is an example of creating a JSON client:
/// A JSON client for the Guild Wars 2 API
struct GW2API: Singleton, ServiceHost {
// 'Singleton'
private(set) static var shared = Instance()
typealias Instance = GW2API
// 'ServiceHost'
static var scheme: String { return "https" }
static var host: String { return "api.guildwars2.com" }
static var path: String? { return "v2" }
}
Any ServiceHost
can make a request. Therefore, a Singleton
that is also a ServiceHost
can, as well:
// Prints the name of all dyes returned by the "colors" endpoint
GW2API.request(endpoint: "colors", parameters: ["ids":"all"])
.startWithResult {
$0.value?.forEach {
print($0["name"])
}
}
Benjamin Encz sums up the philosophy behind ReactiveJSON rather well:
"One of my favorite aspects of Swift: Protocols allow you describe truths about types. Generic code can build on top of these truths."
The Singleton
protocol requires its Instance
alias be a ServiceHost
. Without the need to overload any request
functions, we can create a client that loads its responses from a fixture file. The result might look something like this:
Note: For a complete example of this concept, see
Fixture.swift
class ServiceHostTests: QuickSpec {
override func spec() {
describe("resource json") {
it("handles conformance on assignment") {
var users: [[String:AnyObject]] = []
try! Fixture.request(fixture: "users") { users = $0 }
expect { users.first?["username"] as? String
}.toEventually( equal("Bret") )
expect { users.first?["id"] as? Int
}.toEventually( equal(1) )
}
}
}
}