loading...
Cover image for Application-Driven API Design

Application-Driven API Design

smizell profile image Stephen Mizell Originally published at smizell.me on ・3 min read

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.

Posted on Mar 14 '19 by:

smizell profile

Stephen Mizell

@smizell

I'm a software developer, and I spend a lot of time thinking about APIs, best practices, and culture.

Discussion

markdown guide
 

When I read the title I thought you were going to say one should develop a front end and then bud the backend for it, and I was ready to hit my caps lock.

However while reading I realized this is exactly how I have been doing APIs in my projects, and you were able to put it in words. Great read!

 

I'm a bit confused about what you wish to convey through this article. Do you mean to say that we should try to define the scope of our application by defining each entity interacting with the app before writing APIs?

 

Thanks for the question :) What I'm trying to convey is that we should design APIs by exploring the application logic first. This exploration should happen apart from considerations about HTTP, database design, and system architecture.

Many experts suggest writing an OpenAPI document before writing any code. While this does push for a design-first approach, it forces designers to think in the context of HTTP and JSON. I believe this limits how designers can explore the application's domain.

In contrast to a design-first approach is a code-first approach. For this, people build the API first and then generate an OpenAPI document from it. The problem with this is that it can cause people to skip over the design step—you may get an API, but who knows if it's the right API.

These approaches have merit, but I feel they are lacking. I think it's best for people to find ways to explore the application logic and domain without thinking about external dependencies. An API is a delivery mechanism, and it shouldn't affect your application logic. Same goes for the database. I think the best way is to start by writing some code to test out the logic and then design an API around that.

This fits into a few architectural patterns that I've found very helpful.

I hope I didn't muddy the water :) I'm happy to answer any further questions you have if I didn't quite convey what I'm talking about.

 

Thanks for taking the time to give such a detailed reply!