After Bite #223's "Standard Setup", many readers asked for more detail about the actual architecture involved. Today we'll take a look at an example request, model, and a bit of how data "flows" from the web in to views in the app.
Who? Again it's me, Jake Marsh! I write this thing. Writing in the first person feels quite strange at this point.
Let's start with a Moya setup for one endpoint. I love this convention. It standardizes "what goes where" for HTTP verbs, params, etc. I'm never trying invent, just define it, and move on.
public enum StewardAPI : RxMoya.TargetType {
case Checkins(start: Int)
}
extension StewardAPI {
public var method: RxMoya.Method { return .GET }
}
extension StewardAPI {
public var path: String {
switch self {
case .Checkins: return "/checkins"
}
}
}
extension StewardAPI {
public var parameters: [String: AnyObject]? {
switch self {
case .Checkins(let start):
return ["start": start, "maxResults" : 50]
Next, to actually use this API, I have an small extension I add with a global function called fetch
. This returns an Observable<Decodable>
.
This "calls" the HTTP endpoint, and expects some JSON that can be transformed into one of my defined Decodable
types:
fetch(.Checkins(start: start), type: [Checkin].self).subscribe { event in
switch event {
case .Next(let checkins): print(checkins)
case .Error(let error): print(error)
default: break
}
}.addDisposableTo(rx_disposeBag)
Normally, I wouldn't switch here, I'd map this into a type I use called a "Presenter" (people also call it a "Decorator" or a "View Model").
It is immutable and contains boring business logic. This is what actually gets handed to my view controllers and views:
fetch(.Checkins(start: start), type: [Checkin].self)
.map { ListItemPresenter(item: $0) }
Please send any questions about any of this to hello@littlebitesofcocoa.com. Happy to go in to further detail if there is interest here.