Built to Flex: View-based RESTful APIs

Amit Wadhawan
Aaptiv Engineering
Published in
6 min readNov 8, 2017

You’ve just shipped your latest feature and everything’s going well, except, the requirements have now changed. In your UI, all cityName instances in the tableview need to be replaced with countryName.

What if the endpoint you were using had such flexibility built into it? What if that endpoint let you render a view that was dynamic, flexible and controlled server-side? What if this view let you show various types of objects or change values for current ones without releasing a new version of your app? Well, stick around. This post will introduce you to a design pattern to help you do all the above.

The Need For Flexibility

When compared to mobile apps, deploying changes on the web are much quicker since one doesn’t have the additional app submission and approval process to contend with. Even so, reducing the number of deployments while still being able to make changes on mobile and web clients would be considered a win. This can be achieved by front-loading the effort to make our endpoints, data contracts and UI’s more abstract. This abstraction will provide more flexibility for your UI and let you control business logic server-side, which in turn, may help reduce the need to deploy to make these changes.

The scenario listed above isn’t uncommon, but there are several other advantages that may contribute to us moving towards this design pattern. These include the ability to:

  • Update/rearrange UI elements from the server
  • Run various A/B test variations
  • Avoid the additional release time added from the App Store review process
  • Move business logic to the server and have a single control point to make changes

Typical to Flexible

Now that you’re been convinced, let’s get down to business and see how to make this happen. Let’s take an example of a basic travel app that shows you how much it is to fly to a destination based on your location.

What would the JSON for this view look like?

Typically, you’d have a destination table in your database, which you would pass down in the endpoint. It may look something like the following:

{
"destinations": [{
"id": "1234567890",
"city": "Los Angeles",
"state": "CA",
"country": "USA",
"background": "http://www.example.com/losAngeles.jpg",
"airportCode": "LAX",
"lat": "165.0987654",
"lon": "45.3456788",
"flightPrice": "180"
},
{ and so on...

Using a view-based API, we could represent the same view with the following JSON:

{
"data": [{
"backgroundImage": "http://www.example.com/losAngeles.jpg",
"title": "Los Angeles",
"subtitle": "$180 Roundtrip",
"objectID": "1234567890",
"type": "airfare"
},
{ and so on...

Let’s break down what’s happening here.

We completely ignore the original data model and switch our focus to the view that we need to represent. We then abstract out all the elements of the view, use generic names to represent them so they’re not tied to a specific type of data like price or location. Once we’ve done that, not only have we removed all the extra data being sent down but we’ve also decoupled the view from the data. Now whatever value the server sends us for title or subtitle will be shown in their respective views. We have also changed the id to objectId because we want this value to be opaque to us. Read along and you’ll see why.

Time to Flex

Consider this scenario: Our application is expanding to include other types of products such as hotels, but we also want to be able to link out to blogs that we think our users will find interesting and gain inspiration from. Let’s see how we would manage that with the view-based API.

{
"data": [{
"backgroundImage": "http://www.example.com/losAngeles.jpg",
"title": "Los Angeles",
"subtitle": "$180 Roundtrip"
"objectID": "1234567890",
"type": "airfare"
},
{
"backgroundImage": "http://www.example.com/hotel.jpg",
"title": "The Standard Hotel",
"subtitle": "$220 per night"
"objectID": "456789876",
"type": "hotel"
},
{
"backgroundImage": "http://www.example.com/blog.jpg",
"title": "Top 10 Summer Getaways",
"objectID": "http://www.someblog.com",
"type": "blog"
},
{ and so on...

Time to break it down again.

Our first item on the list stays the same. In the second one, we’re able to add in a hotel with the same JSON data contract that we’d made for flights. Since the view we have will remain the same, the only difference is the values of the data passed down. This brings us to the type and objectId.

These two are where the meat of the content lies. You’ll notice that even though we’ve included three different types of objects in the view, all that changes is the type. The type value lets us know where to send the user to. For example, you’ll see that the objectId for the type “blog” is a url. When we see that the value is blog, we can assume that the view will render if we send the objectId to a browser. Similarly, for a hotel, we would pass in that objectId to a view controller that can send the objectId to the server and get back information about that particular hotel.

This design pattern isn’t just limited to a feed view. You can use these for your detail views where you need to A/B test the order of whether you want to show the map above the description or to optimize your checkout flow. The possibilities are endless!

Now that you’ve seen the flexibility that can be at your disposal, let’s get a brief overview of the design pattern that fuels this API.

The Entity-Control-Boundary Design Pattern

Entity-Control-Boundary (ECB) design pattern UML

The Entity-Control-Boundary (ECB) design pattern is a variation of MVC that is used for systems rather than just user interfaces. Let’s break down the various components to help illustrate their roles:

  • Entities are objects representing system data: Destination, Flight, Hotel, User, etc.
  • Boundaries are objects that interface with system actors: API endpoints, user interface, gateway, proxy, etc.
  • Controllers are objects that mediate between boundaries and entities. They orchestrate the execution of commands coming from the boundary and serve as the glue between boundary elements and entity elements, implementing the logic required to manage the various elements and their interactions.

Like with MVC, there are rules around the interaction between the various elements:

  1. Actors can only talk to boundary objects.
  2. Boundary objects can only talk to controllers and actors.
  3. Entity objects can only talk to controllers.
  4. Controllers can talk to boundary objects and entity objects, and to other controllers, but not to actors

Ultimately, the goal is the separation of concerns between application layers. This architecture, and many like it, aren’t dependent on presentation models or platforms. All the arrows, or dependencies, point inwards in the abstraction chain, each successive layer less abstract than the one before it.

For further reading on this design pattern, please refer to the following links:

Conclusion

As with many design patterns, there are pros and cons to using each. ECB allows for the implementation to abstract your business and view logic away from your models and build a database-agnostic architecture. No design pattern can be used as the proverbial silver bullet, but ECB is definitely a useful tool to have in your chest when you want to control the actor(s) from the server-side or when there’s a need for flexibility.

--

--