• Phil Ledgerwood

There Are No RESTful Urls

Imagine that you're creating a REST API for a product catalog service, and you're building the endpoint to view a product by id. Which of the following is the most RESTful URL to use?

  1. mystore.com/products/17

  2. mystore.com/product/17

  3. mystore.com/product?id=17

  4. mystore.com/aggabaggadagga

The answer is: they are all equally fine in terms of REST.

REST does not accomplish discoverability through the URL. In fact, the URL does not need to have any meaning at all to be RESTful. The only thing it does need to be is a unique locator of a resource that consistently locates that same resource.

In Roy Fielding's dissertation "Architectural Styles and the Design of Network-based Software Architectures", he writes:

At no time whatsoever do the server or client software need to know or understand the meaning of a URI — they merely act as a conduit through which the creator of a resource (a human naming authority) can associate representations with the semantics identified by the URI.

In other words, there is no inherent meaning that has to be in the URI. You can do whatever you want, although since human beings are designing these locators, semantics will probably be a useful by product.

Keep in mind that REST is defined by the HTTP protocol, which is primarily the focus of Fielding's dissertation. When you click around websites, check out the URLs. Sometimes, they seem to be very semantically clear. Sometimes, they don't. Sometimes, they seem to follow a discernible pattern. Sometimes, they don't. It doesn't matter because the way you navigate web pages is through hyperlinks supplied by the resource (hypermedia), not by figuring out the URL scheme.

As organizations have tried to adopt REST, a number of opinions have cropped up about how your endpoints ought to look. Patterns and recommendations emerge. People think your URLs should be human readable. They think they should follow a certain replicable pattern. They think the world would be a better place if everyone followed the same pattern - and so on.

There may very well be merit to these proposals, but as far as REST is concerned, your URLs can look however you want following whatever patterns you want or none at all.

What's The Point, Phil?

The point is that I am so smart and know lots of things.

Just kidding! (About that being the point, I mean.) The reason I want to point this out isn't to be right about stuff, but rather that this has important implications for how your organization designs your APIs.

The first point is good news: you no longer have to debate what the "most RESTful" URL is for a particular endpoint. HTTP simply does not care if you use plurals or singulars, if you put stuff in the address segments or the query string, or if you use nouns, verbs, adjectives, or dangling participles. This is really good news for everyone except the people who like to make authoritative pronouncements on such things.

HTTP only cares that your URLs are unique locators that consistently lead to the same resource and that the HTTP methods you use with those URLs act consistently with the HTTP specification (e.g. GET, PUT, and DELETE are idempotent). What combination of letters, numbers, and slashes you choose to use is completely up to you. Use all that time you'd normally have used to debate the RESTfulness of plurals vs. singulars for debating the media types you want to use.

However, with great freedom comes great responsibility. If you can make your URLs however you want, you can quickly come up with a complicated mass of URLs that is difficult to work with. I can't tell you what the right pattern is for your project, but here are some things you might want to think about as you design your endpoints.

Should They Be Understandable?

That may seem like a trick question, but it's definitely something you should ask yourself about your API endpoints.

For example, take this URL: mysite.com/products/17

If I see that URL, I can conclude that there are probably products 1-16, and I can just change the number at the end of the URL to get details about other products.

Is that good? Well, if you're trying to get your product info out into the world, it probably is. But consider this URL: mysite.com/employees/17/personaldata.

Well, that URL is definitely readable, understandable, and I might say "hackable." But is this good?

It's probably very easy for your internal developers to work with, but what if someone on the outside saw that URL? People could probably determine that they could at least request the personal data of any employee if they just found the right number.

Depending on the security, audience, intent, and exposure of your API, you may want some of them to be difficult to understand and the pattern difficult to discern just by reading.

How Important is Business Intent?

HTTP works like this (very imprecisely): a client issues a request to a server using a unique identifier to a resource, a method they want to use with respect to that resource, and pertinent other data in the header or the body of the request (e.g. media type, data extracted from a form, etc.). The server responds with a resource that reflects the state of something the server has to offer.

In other words, HTTP - and therefore REST - is primarily concerned with resources and state, not business functionality, business logic, etc.

Insofar as your application is concerned with resources and states, REST and what is popularly considered to be "RESTful URLs" might be a good choice. The more your application is focused on things like maintaining a store of requestable data, the better these choices become. If someone is creating a CRM or a reporting app or a place to store recipes, the heart of these projects is maintaining requestable resources.

However, many apps we write that consume APIs are not focused on requesting resources or maintaining the underlying state of these resources. They are not primarily front-ends over databases (or they shouldn't be, at least). They are about business operations and getting things done.

One of the advantages of using RPC for APIs is they were pretty good about communicating the intent of the endpoint. Most of them even supplied WSDLs that the programming language of your choice could use to generate proxy classes that you instantiated and called just like any other object in your application. Your endpoints were called things like "cancelorder" as opposed to being a PUT request to "orders/17."

A downside of this is that you basically needed the manual to use the API. There was no telling what methods were available, what data they needed in their parameters, or what you'd get back without referring to the documentation. But the endpoints did reflect the intent.

"RESTful URLs," by contrast, tend to not communicate this at all. Let's say I want to cancel an order. What's the "RESTful URL" for that? Is it a PUT request to orders/17? What if I want to change one of the line items in the order? Or change the shippping address? Or make it a gift? Are those all PUT requests to orders/17?

What if cancelling an order has side effects besides just changing the state of an underlying order? What if it sends an email to customer service? What if it changes my Inventory? How much of that ends up being hidden under a PUT request to orders/17?

I'll never forget one of my earlier experiences with "REST" when a client was trying to make endpoints for a very rich resource and exclaimed, "I'm running out of HTTP verbs, here!"

One thing you have to consider is if you want your URLs to reflect some kind of intent. Keep in mind, this is 100% fine as far as REST is concerned. Just keep in mind that the URL locates a resource; it is not a remote procedure call. This issue may call into question whether REST is right for your API at all, and it's certainly fine for it not to be!

It is possible to keep to what has become sort of the default for REST URLs and still reflect intent simply by thinking of the business events that can occur in your system as accessible resources.

For example, we could accomplish cancelling an order by issuing a PUT to orders/17, but we could also accomplish it by issuing a POST to orders/17/cancellations. Not only does this put intent in the URL, but it also encourages us to consider things like commands, queries, and events as first-class citizens in our API and our domain models. This opens the door to patterns like CQRS, event sourcing, and bare minimum gives us the option of easily storing or tracking these events for auditing purposes or later analysis.

The point is: REST does not care. Come up with whatever URL is useful for you. Use all that saved debate time to argue about media types and status codes.


© Integrity Inspired Solutions, LLC. All rights reserved.

  • Black Facebook Icon
  • LinkedIn Basic Black
  • Twitter Basic Black
  • Black RSS Icon