Question

I've come up with the mapping that follows while working on the REST API of a system where users are able to create and manage resources of different types.

// READ OPERATIONS
GET /objects               => read collection meta
GET /objects/[id]          => read single element
GET /objects/?[query]      => read a number of elements
GET /objects/?all          => read all elements

// CREATE / UPDATE OPERATIONS
PUT /objects               => possibly create the collection and update its meta
PUT /objects/[id]          => possibly create and update a single element
PUT /objects/?all          => update the entire content of the collection
POST /objects              => create new objects or update existing objects
PATCH /objects             => partially update the collection meta
PATCH /objects/[id]        => partially update a single element
PATCH /objects/?all        => partially update all the elements
PATCH /objects/?[query]    => partially update a number of elements

// DELETE OPERATIONS
DELETE /objects            => delete the collection
DELETE /objects/[id]       => delete a single element
DELETE /objects/?all       => empty the collection
DELETE /objects/?[query]   => delete a number of elements

Here's some more information on the system:

  • each resource can be either be a simple one or a collection-like one;
  • each resource, collection or not, has properties of its own that need to be accessed and manipulated;
  • the API must support bulk (not batch) operations.

I've also examined the following alternatives:

  1. using /collection to access the collection's set of elements and /collection?meta to access the collection's own data;
  2. using a whole new resource to access a collection's own data, such as /collections/path/to/collection.

I do not like alternative n. 1) because it feels, to me, semantically poor. By comparison, when I refer to a box I am actually referring to the box in itself and not to its content.

I do not like alternative n. 2) because a resource ends up having its own data exposed by another resource, duplicating urls and making the problem of "which url should I use" not that trivial as I'd like it to be.

Therefore, my questions:

  1. Is the mapping I have proposed a valid, proper mapping for a REST API? Is it respectful of REST principles? I'm not asking whether it's the best mapping out there or not. I'm asking about its validity.
  2. If not, which one of the alternatives is the better one and why?

Please excuse my english, I'm not a native speaker of the language.

Was it helpful?

Solution

I thought the API design looked OK, but then I re-read this comment of yours at the start:

where users are able to create and manage resources of different types.

If the resources of your system are of different types, why are you exposing them with a neutral, type-less API that works only with generic objects?

The first part of RESTful API design is the identification of the nouns in your system, and those nouns should be considered strongly as candidates for exposure as URIs. I would strongly encourage you to try and get more specific than object and model the business functionality of your system with clearer URIs.

And your English is fine!

OTHER TIPS

First of all, the semantics of URIs aren't relevant to REST. "RESTful URI" is almost an oxymoron. The only constraint an URI must follow to be RESTful is that it references one and only one resource.

Obviously, that doesn't mean REST URIs can be obscure. They should be as clear, intuitive and descriptive as possible, but whatever scheme you decide to use is fine, as long as its consistent. If you're so concerned with this, it means you're probably not using HATEOAS and should take a look at it.

Second, you're not considering the media types, and that's why you end up with the problem of using URIs to designate different media types. Let's say that retrieving all elements of a collection should be simply:

GET /objects

And retrieving a single element of a collection should be:

GET /objects/[id]

Now, if the client needs only the metadata for a resource, either a collection or a single element, it should specify that through the Accept header, not by going to a separate URI you point to in the documentation, or even worse, by adding query string parameters.

So, for instance, if the media type for your object is application/vnd.mycompany.myobject+json, your clients get the full object representation when using that media type in the Accept header, and get the metadata by using something like application/vnd.mycompany.myobjectmetadata+json.

I guess this probably isn't what you expected, but that's what REST is. Your documentation and design effort should be focused on your media types, not your URIs. When you use HATEOAS, URI design is irrelevant, and if you're not using HATEOAS, you're not using REST.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top