Stephen Mizell

Application-Driven API Design

March 14, 2019

When designing APIs, it’s important to take a design-first approach to ensure the right API gets built. However, I don’t think the first step should be to write an OpenAPI or API Blueprint document. I think it should be to design a working application.

To take this application-driven approach to API design, API designers should start the API design process by creating an application that allows them to explore the domain and try out the design all without considering data storage, web interactions, or architecture. It produces a better design and is a better step for beginners to take.

An example of this approach

Let’s say we’ve been asked to design an API for managing tasks. We’ll keep it basic for now. We’ll say requirements are to provide a way to manage tasks that have a description and a way to mark them as complete. We’ll need to filter the tasks on the their status. Instead of starting with an API description for this, we’ll first write a tiny application in Python—any language would do.

from dataclasses import dataclass

task_storage = []

@dataclass
class Task:
    description: str
    is_complete: bool = False

def mark_task_complete(task):
    task.is_done = True

def mark_task_incomplete(task):
    task.is_complete = False

def store_task(task):
    task_storage.append(task)

def all_tasks():
    return task_storage

def completed_tasks():
    return [task for task in task_storage if task.is_complete]

def incomplete_tasks():
    return [task for task in task_storage if not task.is_complete]

At this point, we could drop into a REPL and explore the design. Does it feel right? Is our vocabulary correct? Are we missing some functionality? Through this we’ll see operations that are safe and others that alter state and are unsafe. This is all useful knowledge that can drive the API design.

Also look at all the things we’re not doing in this step. We’re not installing mock servers, JSON schema validators, or documentation tools. We’re not forcing ourselves to think in the context of URLs and HTTP. We can push these details to later because—while important—they come second to the application design.

How this affects beginners

Our code above would be simple enough to talk through with people completely new to programming. We would be able to discuss the problem and the domain with beginners and not have to start with details related to building an HTTP API. Once we have a good feel for our application, we can start asking the questions about how we might persist the data or make the functionality available over the web. It’s a much better starting place than URLs and HTTP requests.

I have a hunch that experienced API designers do this application design in their head as they write API definitions. They’ve been through the process and used APIs enough to know what works and what doesn’t. However, I’ve found there is a lot to gain by writing applications first to drive the API design.

This is nothing new

This process for writing code to explore a domain isn’t new. There is a great presentation called Domain Modeling Made Functional where the presenter walks through how he uses F# and static types to define the domain. He concludes, “The design is the code and the code is the design.” His point is that you can capture the domain in code and use the tools around F# to explore the design.

We could do the same with API design if our first step is to define and explore the domain. If we can do this in code, we can give our application a test drive before ever thinking about the API specifics.