URL Design for RESTful Web Services

URL design discussions for RESTful web services often degrade into debates over pluralization and parameter names. There are a couple of principles I like to use to keep things simple.

1) Using your API should feel like using a filesystem

  • Endpoints used to create, list, and search for entities should look like directories, e.g. /users
  • Use a plural noun so it feels like a directory of users, not a user controller
  • Endpoints used to read, update, and delete individual entities should look like files, e.g. /users/charlie

2) All calls to a given endpoint should return the same type

  • Either apples, or oranges, or a list of oranges, don’t mix them up
  • File-looking endpoints should return individual entities
  • Directory-looking endpoints should return lists of entities


We may be bikeshedding here but I think your API will be more intuitive to newcomers if you model it this way.

  • Consistent response type per endpoint simplifies deserialization for clients, no switching needed
  • Once you agree on a contract it’s easy to mock up with static files on a server
  • Clients can start working with your mockup before your code is finished

Example Operations on Endpoints that look like Files

Read

GET /users/charlie
200 OK
{username: charlie, state: VA}

Update

PUT|PATCH /users/charlie
[password=1111]

Delete

DELETE /users/charlie

Example Operations on Endpoints that Look Like Directories

List

GET /users?start=40&count=20
200 OK
[{username: charlie, state: VA}, ...]

Search

GET /users?q=cha

Create

POST /users
{username=charlie&password=1234}
201 CREATED
Location: /users/charlie

Directory endpoints are supposed to return lists (or nothing).  So send back a pointer to the new user record, rather than the user data itself.

PUT /users/charlie

Also ok IFF you allow clients to generate entity ids

Serious Bikeshedding


Here’s other stuff I like:

Use a filename extension instead of the Accept header to express the response format:

http://api.example.com/users/charlie.json

  • Not pure REST but it makes your API easier for devs to poke with curl and the browser. Easier to use means better adoption!
  • Friendlier on stupid caches that improperly handle headers since the endpoint always sends back the same bytes (within the ttl)
  • You can use .html (or no extension) to request the web representation and serve your API and web views with the same controller logic (though this can turn into a rabbit hole)

Another vote against the Accept header: version your endpoints in the URL, at web-application level:

http://q.addthis.com/feeds/1.0/trending.json?pubid=atblog

  • feeds.war is the webapp and 1.0 is the version of the released artifact (which is 1.0.3 internally)
  • Version numbers should correspond to deployable artifacts so they’re easier to manage
  • You’ll need to keep old versions online in real-world use cases

Dropwizard has a nice model for organizing your projects.

Some javascript/flash API consumers will pressure you to add a suppress_response_codes parameter and always send them a 200. You’ll hate it but will end up giving in (just wait).

  • You’ll need to define a standard error response envelope that they can switch on to check for errors and extract the reason. It will get messy for them and they will lose a lot of the benefits of this design.
  • Anyone have better ideas here?

11 thoughts on “URL Design for RESTful Web Services

  1. Pete Johanson

    I don’t understand why “makes your API easier for devs to poke with … the browser” is so important at this point.

    With a plethora of useful ReST/HTTP plugins/tools (e.g. search “rest client” in the Chrome Web Store”), why should exploring using the lowest common denominator dictate your technical decisions?

    Reply
    1. Aaron Jorbin

      The browser is most likely the tool you used to discover the API and the tool you are using to read the docs for the API, thus it completely makes sense to make it the tool you use to quickly play with the API and decide if you’re going to use. I completely agree with Charlie here.

      Reply
    2. Charlie Reverte Post author

      In terms of the API user experience it’s pretty sweet to be able to link users to actual calls from within your online docs. If you have good linking between your endpoints you can do a fair bit of navigation around the API in your browser before you need to reach for curl or fancier clients. It makes for a better first impression which improves the likelihood that someone will implement.

      Reply
  2. Adrien Risser

    What about the best URL designed in REST as is “/”?
    API URLs don’t matter when everything is hyperlinked.
    (As in a Website, who likes to type every single page link in the browser?)

    Reply
  3. Pingback: URL Design for RESTful Web Services | Output Translation

  4. mahemoff

    I think POST /users/charlie should be a PUT (more bikeshedding).

    Creation can happen by either POSTING to the generic resource /users or PUTting to a specific instance (if it’s allowed for the client to name the resource, as you point out).

    Reply
  5. Pingback: Review: Google Glass API | API UX

Leave a Reply