Fabricio Rocha Fabricio Rocha - 1 month ago 7
reST (reStructuredText) Question

How to offer lists of valid values for parameters in a RESTful API?

This is more a conceptual than technical question, I guess. Suppose I have a REST API for dealing with a huge rent-a-car fleet.

The API is modelled around the business entities/resources in the very standard and coherent (even if controversial) way like that:


  • /cars/1234
    - detailed data about a certain car

  • /clients/5678
    - detailed data about a certain client

  • /cars
    - a list of cars and their URIs

  • /clients
    - a list of clients



However, the fleet is huge and a list of all cars is not that useful. I would rather have it filtered, like:

GET /cars?type=minivan


For properly using the "
type
" parameter, I should have a list of valid values such as "minivan", "convertible", "station-wagon", "hatchback", "sedan", etc. Ok, there are not that many kinds of cars out there, but let´s suppose this list is something too big for an enum in the API´s Swagger definition.

So... What would be the most consistent and natural way for a REST API to offer a list of valid values for a query parameter like that?


  • As a subordinated resource like
    /cars/types
    ? This would break the
    /cars/{id}
    URL pattern, isn´t it?

  • As a separate resource such as
    /tables/cars/types
    ? This would break the consistency around the main resources of the business model itself, right?

  • As part of the body of a response for
    OPTIONS /cars
    ? It looks like the "RESTfullest" way to me, but some of my coworkers disagree, and OPTIONS seems to be rarely used for things like that.

  • Maybe as part of a response to
    GET /cars?&metadata=values
    or something alike? The "values" here would seem more semantically related to the returned data than to the query parameters, isn´t it?

  • Anything else?



I have googled and searched in SO for some recommendations about this particular subject, but I could not find anything to help me with arguments for such a decision...

Thank you!

Fabricio Rocha

Brasilia, Brasil

Answer

"a good REST API is like an ugly website" -- Rickard Öberg

So how would you do it in a website? Well, you'd probably have a link that goes to a form, and the form would have a list control / radio buttons with semantic cues for each option, with the expectation that the user would select a value from the options available, and the user agent would encode that value into the URL of the GET request when the form was submitted.

So in REST, you do the same thing. In the initial response, you would include a link to your "form" resource; and when a user agent gets the form resource you return a hypermedia representation of your form, with the available options encoded within it, and when the form is submitted your resources pick the client choice(s) out of the query part of the identifier.

But you probably aren't doing REST: it's a colossal PITA, and the benefits of the REST architecture constraints probably don't pay off in your context. So you are likely just looking for a reasonable spelling of an identifier for a resource that returns a message with a list of options.

As a subordinated resource like /cars/types ? This would break the /cars/{id} URL pattern, isn´t it?

Assuming your routing implementation can handle the ambiguity, that's a fine choice. You might consider whether there's just one list, or different lists for different contexts, and how to handle that.

As a separate resource such as /tables/cars/types? This would break the consistency around the main resources of the business model itself, right?

Remember OO programming and encapsulation? Decoupling the API from the underlying data model is a good thing.

That said, I'm personally not fond of the "tables" as an element in your hierarchy. If you wanted to head that direction, I'd suggest /dimensions -- it's a spelling you might use if you were designing a data warehouse

As part of the body of a response for OPTIONS /cars ? It looks like the "RESTfullest" way to me, but some of my coworkers disagree, and OPTIONS seems to be rarely used for things like that.

Yikes! RFC 7231 suggests that a very confusing idea.

The OPTIONS method requests information about the communication options available for the target resource, at either the origin server or an intervening intermediary.

(emphasis added). When writing APIs for the web, you should always be keeping in mind that a client request may go through intermediaries that you do not control; your ability to provide a good experience in those circumstances depends on not confusing the intermediaries by deviating from the uniform interface.

Maybe as part of a response to GET /cars?&metadata=values or something alike?

For the most part, machines are pretty comfortable with any spelling. URI design guidelines normally focus on the human audience. I think that particular spelling will confuse your human consumers, especially if /cars?... would otherwise identify the resource that is a search result.

Anything else? I still feel that what people expect to find under /cars is... a bunch of cars (their representations, I mean), not a list of values among them...

So let's change up your question a little bit

What would be the most consistent and natural way for a REST API to document a list of valid values for a query parameter like that?

If there's one thing the web is really good for, it is documenting things. Pick almost any well documented web API, and pay careful attention to where you are reading about the endpoints -- that will give you some good ideas.

For instance, you could look at the StackExchange API where

https://api.stackexchange.com/docs/questions

tells you everything you need to know about the family of resources resources at

https://api.stackexchange.com/2.2/questions

Types, unsurprisingly, are documented like:

https://api.stackexchange.com/docs/types/flag-option

If you wanted to be sexy about it, you could use Accept-Type to negotiate a redirect to either human readable documentation or machine readable documentation.