URL

API Design: Stability Versus Readability—Must One Choose?

Good API design separates APIs that merely expose assets from those that help developers get things done. As I’ve written before, and as we’ll explore in this article, good design includes the style in which web API URLs are constructed.

Below are two API URLs that exemplify two divergent schools of thought on URL style. The first example is an anonymized and simplified version of a real URL and the second is a theoretical URL:

https://ebank.com/accounts/a49a9762-3790-4b4f-adbf-4577a35b1df7

https://cinemacanon.com/genre/documentary/film/los-angeles-plays-itself

Some major differences are obvious:

  • The first URL is opaque, providing enough information for a human to infer that the URL references a bank account at ebank.com, but nothing else. For those without a photographic memory, the URL details will be difficult to remember and difficult to distinguish from other, similar-looking URLs.
  • The second URL is much easier to interpret, memorize, and compare with other URLs. It tells a clear story: Los Angeles Plays Itself is a film in the documentary genre, and it is listed, along with other films in other genres, among the offerings on the fictional Cinema Canon website.

Because the second example is much friendlier to humans and because APIs are products used by human developers, it may seem that the hierarchical style is preferable. This is not always the case, however.

Conitnue reading this article on Medium.

API Design: Choosing Between Names and Identifiers in URLs

If you're involved in the design of web APIs, you know there's disagreement over the style of URL to use in your APIs, and that the style you choose has profound implications for an API’s usability and longevity. The Apigee team here at Google Cloud has given a lot of thought to API design, working both internally and with customers, and I want to share with you the URL design patterns we're using in our most recent designs, and why.

When you look at prominent web APIs, you'll see a number of different URL patterns.

Here are two API URLs that exemplify two divergent schools of thought on URL style:

https://ebank.com/accounts/a49a9762-3790-4b4f-adbf-4577a35b1df7
https://library.com/shelves/american-literature/books/moby-dick

The first is an anonymized and simplified version of a real URL from a U.S. bank where I have a checking account. The second is adapted from a pedagogic example in the Google Cloud Platform API Design Guide.

The first URL is rather opaque. You can probably guess that it’s the URL of a bank account, but not much more. Unless you're unusually skilled at memorizing hexadecimal strings, you can’t easily type this URL—most people will rely on copy and paste or clicking on links to use this URL. If your hexadecimal skills are as limited as mine, you can’t tell at a glance whether two URLs like these are the same or different, or easily locate multiple occurrences of the same URL in a log file.

The second URL is much more transparent. It’s easy to memorize, type and compare with other URLs. It tells a little story: there's a book that has a name that's located on a shelf that also has a name. This URL can be easily translated into a natural-language sentence.

Which should you use? At first glance, it may seem obvious that URL #2 is preferable, but the truth is more nuanced.

Read the whole story on the Google Cloud Platform blog.

The False Dichotomy of URL Design in Web APIs

There are two schools of thought on how to design URLs in web APIs, and they often turn into warring factions. Here at Apigee, in the past, we have seen very heated discussions on this topic, with the ultimate resolution often being made arbitrarily by whomever controlled the particular API under discussion. 

Recently, we’ve arrived at a common view on the topic, which has restored team harmony and—we believe—resulted in better APIs. We thought we'd share our secret.

URLs for stability

One of the historic schools of thought (typically the minority one) was populated by people who were steeped in the web. In that tradition, URLs are stable identifiers of web resources. The format of the URL is controlled by the server and should be opaque to clients. In other words, the URL format of a resource is not part of the API. 

Because there’s a strong requirement for stability over time, the guidance is to try not to encode any information in the URL. For a library inventory system, URLs in this style might look like this: 

https://libraries.gov/books/85ab9db7-abfd-46c4-823b-ad6997b96509

There is a very famous document entitled "Cool URIs don't change" by Tim Berners-Lee, the inventor of the web, explaining the rationale for URLs like this. It contains this quote:

"After the creation date, putting any information in the name is asking for trouble one way or another."

Even putting the word “book” in the URL above is questionable—if we switch to digital media, is it still a book or is it now a CD?

URLs for humans

URLs designed for stability like this one are sometimes called permalinks. They might appeal to your inner engineer: they are like well-designed primary key values at the scale of the world wide web.

However, they aren’t friendly to humans, and the majority of API designers has decided that being friendly to humans is more important than web theory. So they’ve invented URLs for books that look like this:

https://libraries.gov/library/sunnyvale/shelf/american-classics/book/moby-dick

URLs like this work well because they align with two very powerful techniques that humans use to think and talk about things: we give them names and we organize them in hierarchies. These techniques are older than recorded history.

URLs like this are everywhere in API design, and they are effective. However, systems based on them typically face the problem that renaming entities and reorganizing hierarchies is difficult or impossible. 

Apigee—and more broadly Google (and most other prominent web companies)—offers products today that display these limitations. Unfortunately, it often turns out that the ability to rename entities and reorganize hierarchies is more important and more frequently needed than the product designers initially envisioned.

A unified approach to URL design

After a fairly extended period of debate and polarization within Apigee, we came to understand that picking between these two URL design approaches is a false choice. It is not only reasonable to do both, but for a high-quality API it is usually necessary. We also discovered that there is a very simple idea that neatly unifies the two.

The insight that helped us unify these approaches is that the URL https://libraries.gov/library/sunnyvale/shelf/american-classics/book/moby-dick isn’t actually the URL of a book—it's the URL of a query or, more precisely, a query result.

The meaning of the query is "that book whose title is [currently] 'Moby Dick' that is [currently] on the shelf named 'American Classics' at the Sunnyvale City Library." The same query could have been expressed using a URL that included a query string. The difference is one of URL style, not meaning.

Queries are very useful for locating things, but they have the characteristic that they are not guaranteed to return the same thing twice. The URL above may today return the book whose URI is:

https://libraries.gov/books/85ab9db7-abfd-46c4-823b-ad6997b96509

But tomorrow it might not return anything, or it may return a different thing altogether.

Recognizing that these two URLs are actually the URLs of two different things—a book and a query result—rather than two different URLs for the same thing made it obvious that the right solution was to implement both. 

Most of Apigee's more recent APIs do exactly this. This enables us to simultaneously have cool, stable permalink URLs for identifying entities, and human-friendly query URLs for finding them based on information that humans typically know. This in turn enables us to rename entities and reorganize hierarchies without breakage.

API clients have to be thoughtful about which URLs to use. For example, if a client wants to store a persistent reference to an entity, then that client should use the permalink URL of the entity, not the query URL that today happens to return the same result.

This is very important for internal services, like a permissions service that stores access control rules for entities, as well as for external clients. Following this guidance throughout a system is necessary to ensure that entities can be renamed and hierarchies reorganized without breakage.

Connecting queries and entities is also important. Whenever a query URL is used in an HTTP request, our newer APIs always return the permalink URL in the Content-Location header of the response (and in the response body too) to ensure that clients always have access to the stable permalink URL when they need it.

Happy teams and better APIs 

That’s the story of how we restored peace and harmony to API design teams in Apigee. Part of the reason this worked well is that neither of the original schools of thought had to admit that they had been wrong—they just had to acknowledge that their view had been incomplete, and that they had something to learn from the other school.

We think that the result is not only happier teams, but better APIs.

For more on URL design and a host of other best practices, download the eBook, “Web API Design: The Missing Link.

Image: Noun Project / Roselin Christina.S

How to Improve your APIs with Hyperlinks

If you follow discussions about API design, you will know that the topic of hyperlinks draws a lot of controversy. There are certainly aspects of the use of hyperlinks that are worthy of debate, but we think that adding basic hyperlinks to an existing API, or designing them into a new one from the start, is a simple thing to do and makes the API much easier for users.

Here is an example of a simple API that doesn't have hyperlinks. Most of you will be familiar with the style of API this example illustrates. Here is what a "Dog" resource looks like:

{ "id": "12345678",

 "type": "Dog"

 "name": "Lassie",

 "fur_color": "brown",

 "owner": "98765432"

}

This is what a "Person" resource looks like:

{ "id":"98765432",

 "type": "Person"

 "name": "Joe Carraclough",

 "hair_color": "brown"

}

The documentation tells us that the API exposes these URLs and URL templates, and tells us how to use them:

http://example.org/persons

http://example.org/persons/{person_id}

http://example.org/persons/{person_id}/dogs

http://example.org/dogs

http://example.org/dogs/{dog_id}

With this knowledge, we can navigate the API, including updating resources and creating new ones.

Enhancement with hyperlinks

The simplest way to enhance this API with hyperlinks is to add these two highlighted lines:

{ "id": "12345678",

 "type": "Dog"

 "name": "Lassie",

 "fur_color": "brown",

 "owner": "98765432",

 "ownerLink": "http://example.org/persons/98765432"

}

and

{ "id":"98765432",

 "type": "Person"

 "name": "Joe Carraclough",

 "hair_color": "brown",

 "dogs": "http://example.org/persons/98765432/dogs"

}

Why is this better?

In the original example, if you had in your hand (or in your client application) the representation of Lassie, and you wanted to get the representation of Lassie's owner, Joe, you would have to look in the API documentation to find a suitable URL template you could use to construct a URL that can be used to locate Joe. In the representation of Lassie, you have an “owner” property, so you're looking for a URL template that takes an “owner” as a variable and produces a URL that locates an owner.

This has several drawbacks. It requires you to go hunting in the documentation. There also isn't really a good documentation convention for describing which property values can be plugged into which templates, so some amount of guesswork is usually necessary, even given the right documentation.

In this example, you would have to know that owners are people, and look for templates that take the ID of a person as a variable. A third drawback: you have to write code that will combine the “owner” property value with the template and produce a URL—the template specification calls such code a 'template processor'. For simple templates, this code is very simple, but it still has to be written and debugged.

In our enhanced design, there is less to learn, and using the API is easier. Joe's URL is right there in the data for you to see, so you don't have to go hunting for anything in documentation, and your client code simply has to pick up the value of "ownerLink" and use it—you do not have to write code to construct it.

Essentially, the server just did what the client would otherwise have had to do—it figured out the relevant URL templates, and which property values could be plugged into them as variables, and it did the variable substitution and provided the results to the client in simple JSON properties.

Note that we have taken nothing away—clients can continue to navigate using the URL templates as before, allowing them to “skip” to resources not anticipated by the server in hyperlinks.

One step better still

Let's add a new resource whose URL is http://example.org:

{"type": DogTracker",

"dogs": "http://example.org/dogs",

"persons": "http://example.org/persons"

}

Here's what http://example.org/dogs looks like. It hasn't changed from the original, with the exception of the addition of the highlighted line, which you have already seen:

{"type": "Collection",

"items: [

    {"id": "12345678",

    "type": "Dog"

    "name": "Lassie",

    "fur_color": "brown",

    "owner": "98765432",

"ownerLink": "http://example.org/persons/98765432"

    },

    … other dogs here …

  ]

}

http://example.org/persons/98765432/dogs is similar, and

http://example.org/persons follows the same pattern.

Why is this better?

At this point, our API is fully connected. If I have a suitable browser or browser plugin, I can point it at http://example.org and browse through the entire API without having to look in the documentation and without any special tools or metadata descriptions. How cool is that?

Summary page photo: Hide/Flickr