Practicing API-First Design

Danny Baggett
Atlas

--

Typically clients arrive at Bottle Rocket with all their current systems and services in place, which are often already powering existing experiences. If we’re lucky, we’ll have APIs for these services — mobile developers ❤️APIs, especially well designed APIs. However, not all clients have suitable APIs in hand to power the mobile experience they’re desiring or no APIs at all!

We’re always looking to create the best mobile experiences. We spend as much time thinking about mobile design as we do development, they’re both critical. We feel the same about any APIs we develop. The design is very important, even more so when you consider that an API is really the first interface for any mobile and/or web application. This is why we design the API first — we practice API-First design.

API-First

Introduction

API-First Design, in a nutshell, means that the API comes first then implementation. We believe that you’re much more likely to create something the client actually needs or wants with this approach — the mobile developers will likely be happy as well! As we are designing APIs we’re keeping Google’s API Design Guide nearby for good REST API design reference. So, yeah, we’re talking REST APIs.

Since we’re practicing API-First design, let’s see a hypothetical example to get an idea of how this process might play out.

The Setup

Here we are given client X’s first crack at a REST API for their…todo list application. Here are some of the resource paths:

  • /addNewTodoList
  • /getAllTodoLists
  • /updateTodoList/1

When we want to delete a list…?

  • /deleteTodoList/1

This is not looking too good, how about the remaining resource paths.

  • /addNewTodoListItem/1
  • /markComplete/1

Add to what? Complete what? Why are there so many verbs?

Let’s whip out the Google Design Guide to see how we might handle this situation and we’ll find mention of a Resource-Oriented API.

A resource-oriented API is generally modeled as a resource hierarchy, where each node is either a simple resource or a collection resource.

The Transformation

Let’s structure the resource paths into this hierarchy of collections and resources.

  • /todo-lists
  • /todo-lists/1/items
  • /todo-lists/1/items/1

What are the collections? What are the resources?

Collections

  • /todo-lists
  • /todo-lists/1/items

Resources

  • /todo-lists/1
  • /todo-lists/1/items/1

Note: The entire URI path uniquely identifies a resource e.g. /items/1 alone will not point to a unique todo list item.

This API won’t do very much (the verbs have been removed). This is where HTTP methods i.e. GET, POST, PUT and DELETE come into play.

Note: Now is a perfect time to make it clear that we don’t document our actual APIs in CSV format! We’ve primarily used API Blueprint as our description format. API hosting and format will be covered at a later time.

We’ve essentially normalized the API — we’ve removed the verbs. For example, if you want to support deleting a todo list item, just slap on DELETE as an accepted method for /todo-lists/1/items (there’s some real work behind all this obviously).

A Note On Validation

At this point, we have designed a to-do list API. What happens when the implementation arrives weeks or months, hopefully not years, later? How do we ensure that the implementation adheres to the spec? Do we throw the spec out the door? Did API-First go to waste? All of these questions can be addressed by the validation tool Dredd.

Dredd is a language-agnostic command-line tool for validating API description document against backend implementation of the API.

We won't deep dive into Dredd at this point, but here are a few snippets to make you salivate for API validation.

Once installed (with npm), validating an API is as simple as passing Dredd the API spec and the endpoint to validate:

$ dredd todo-list.apib http://127.0.0.1:8080

If everything passes, you will see some comforting output like so:

complete: 19 passing, 0 failing, 0 errors, 0 skipped, 19 total

However, if the server disobeys in the slightest:

complete: 18 passing, 1 failing, 0 errors, 0 skipped, 19 total

We have unit tests for APIs!

Congratulations, we’ve practiced API-First design!

Wait, what about those question marks in the list? Queue the ambiguity.

REST: Art & Science

A normalized form of /markComplete/1 has yet to be provided, partly for suspense, but mainly because it’s the trickiest of the batch. It’s the trickiest mostly because there happens to be, in our opinion, multiple ways to handle this resource path. Let’s end the suspense and give one possible take on it.

Everything might seem ok at first glance but then…complete — a verb! We won't go into too much detail here, but know that a URI must be an identifier for some representation of a resource. It’s doubtful that a URI ending in /complete is some representation of a resource. It’s not. This is likely the case in any other API as well, hence the noun/verb debate. This is all described in the Uniform Interface constraint, one of the 6 constraints of REST.

Let’s handle this problem in a REST-compliant manner and see what that might look like. In fact, it’s pretty easy if we break out the HTTP method, PATCH. This method allows partial resource updates via partial representations.

Assuming that completion of an item is determined by a boolean value, we can have the following list…

…with the following body for the PATCH request (JSON).

{
"completed": true
}

Determining which end of the spectrum to side on in regards to REST compliance will happen in any fashion of API design, from the top or bottom. By designing the API first, these decisions can be made up front and agreed upon by all stakeholders.

That’s about it on this subject…for now.

Summary

We’ve successfully practiced API-First design and swatted away invalid responses with Dredd. It’s been a good day!

--

--