1

I was wondering if anyone out there has general tips for how to structure an iOS app backed by a REST api. There are basically two approaches to this that I've thought of

API calls placed ad hoc in the view controllers.

In this approach the view controller has some state that it fetches from the backend such as a User object and then it renders that User's profile. This approach is simple in that you don't have to deal with any synchronization. You just fetch data when you need it, as if you were rendering a web page.

The downsides of this approach are twofold:

  • Race conditions in viewing / updating models
  • Synchronization problems with instances of models in other view controllers

To illustrate the first point, let's say you have some notification counts on the user profile. When you visit the profile page you fetch the user object but you also want to update the user when they visit a particular tab. So you have two calls:

GET /rest/user  # gets the user
POST /rest/user  # clears notifications

The result is a race condition between fetching the user and updating the notification count. You may fetch a user object without the notifs cleared.

For the second point, you might update the user object but then have other view controllers which depend on the updated user object. Somehow you need to communicate the update to these view controllers.

Treat the app as a cache with a data store that syncs to the API

In this approach all model updates and fetches happen locally via a data interface. The data interface decides when to synchronize itself to the backend and, if it doesn't have some data locally, it blocks callers until the data is available. The downside of this approach is that it's more complicated, you have to deal with cache invalidation, and it's not clear to me how to implement the synchronization.

I want to go this route, but I'm not sure how to proceed. So, I have some questions:

  • Does this data store seem like the right approach?
  • Are there libraries that implement a data store like this? Or examples of projects that go this route?
  • View controllers may fetch instances of objects through the data store, but then these view controllers still need to be aware of communicated updates somehow and I'm not sure how to communicate those updates.
2

I think you've presented two good options here. Which one, or combination of both, works best for you really depends on the data you are working with and how you want to use it. There's probably not enough context for a conclusive recommendation but here are some ideas.

Ad hoc requests

I recommend never allowing your view controllers to access an API directly. In your first proposal I would at least introduce a "service" or "repository" layer. Inject services into your view controllers and have the controller ask its service to perform some action in terms of your domain model ("refresh user profile" or whatever). That at least allows you to group multiple API requests into a single logical operation. A service can make multiple requests and then call a completion block with aggregate success/failure results. A service also gives you one place to introduce client caching, prevent duplicate requests, and so on.

I'd use this if the data you present is rarely shared across different screens or must be refreshed frequently so a client side cache would see little use.

Cached REST/SOAP requests

HTTP caching through a service object shared by multiple controllers could give you a consistent view of your models provided your API routes respond with isolated data (i.e. a request to one route doesn't invalidate the cached response from some other route).

A more complex version might include services storing results in Core Data or some other client side store which can be queried in ways which do not exactly match your API endpoints. Upserting results into a common store can allow one API response to update many related entities. As you noted this then requires that you have some policy for when to delete data from this store (delete instructions from the API, conventions around when to delete any data not seen in the most recent API response, expiration dates on the data itself, or so on). I've found http://jsonapi.org/'s pattern for included objects useful here as a way for an API response to update many related client models.

I'd use this if your data is heavily interconnected, if you usually only update only small portions of the full data set at a time and can reuse the rest, if the client wants to query the same data in lots of different ways, or if you want to support some offline interactions with data once you have it.

Synchronization

When you say "synchronization" I think of APIs which provide an event stream of changes since the last sync. Those events can then be replayed on a client to bring it's local cache up to date. Depending on your use case this might also demand the ability to request a snapshot of the model at a recent point in time to start from so that every client doesn't attempt to replay the entire ever-growing event history. That way a client that has fallen sufficiently out of date can give up, request a recent snapshot, and begin syncing from there.

That sort of synchronization can work well for streams of updates which arrive unpredictably and not in response to action from the client's user but it requires a backend that can produce such an event stream. Depending on your needs this could be a sequence of messages in an IRC room or operational transforms updating a document (e.g. Etherpad).

I'd use this for constant or unpredicatable but frequent updates or if your domain would allow full offline editing of your data and re-synchronization of those changes later.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.