1

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.

Jacoscaz
  • 159
  • 1
  • 7
  • 1
    Your English is great. Your API design isn't bad either :) – Brian Kelly Jan 23 '14 at 18:42
  • Maybe I should open a question for my comment, but I'd like to know what's the difference between the "PUT" and "PATCH". In the server, which actions you will execute in each of them? I'm asking because they look very close. Programmatically are they different? – Eduardo Briguenti Vieira Jan 23 '14 at 19:36
  • @edubriguenti: PATCH allows for partial updates (PUT always requires the whole resource body). Also, it is neither idempotent nor safe (PUT is idempotent). PATCH is, IMHO, more suitable for bulk updates where you just want to update a given subset of properties in a specific set of resources. The same applies for POST vs. PUT. I don't think idempotent methods should be used for bulk updates. – Jacoscaz Jan 24 '14 at 11:03
  • @BrianKelly: turn your comment into an answer so that I can flag it as accepted. – Jacoscaz Jan 24 '14 at 11:05

2 Answers2

1

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!

Brian Kelly
  • 19,067
  • 4
  • 53
  • 55
  • Even though the mapping I have proposed was meant to be a generic example of how to deal with both meta and elements of a collection, your observation is spot-on and definitely to be kept in mind. Thanks! – Jacoscaz Jan 25 '14 at 10:00
1

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.

Pedro Werneck
  • 40,902
  • 7
  • 64
  • 85
  • I get what you're saying about HATEOAS and that is precisely why I'm looking into JSON-HAL and JSON-LD. I really like JSON-HAL information model in the way it deals with sub-resources. That said, whatever the value of the "Accept" header might be, a proper REST API should (AFAIK) always output a representation of the same resource per given URI, whatever the hypermedia type of that representation might end up being. – Jacoscaz Jan 25 '14 at 10:20
  • Perhaps I have been unclear about what I mean by "meta" and probably used the wrong word. Consider a resource, specifically a collection of resources, that has a user-editable configuration of its own. That's what I intended for "meta". – Jacoscaz Jan 25 '14 at 10:23
  • After more reading and looking into REST-related documents and documentations, I now understand the mistake in my URI-first approach. Thank you, Pedro, for pointing me in the right direction. While I still can't wrap my head about the "Accept" header thing, I realized I have approached the whole meta/elements issue from the wrong angle. – Jacoscaz Jan 25 '14 at 16:24
  • A "proper" REST API should simply follow the standards for the underlying protocol. With HTTP, if the client wants a different representation for a given resource, he changes the media-type, not the URI. For instance, you can return a machine friendly representation when the client requests JSON, and a human friendly representation when he requests text/html. – Pedro Werneck Jan 25 '14 at 17:12
  • Yes, that I understand and fully agree with. What I do not understand is why you suggested to use the "Accept" header to choose which part of the resource (meta vs. elements) to be included in the representation. That's not the same thing, at least as far as I understand, as simply asking for a certain representation of a resource. – Jacoscaz Jan 25 '14 at 19:14
  • The whole issue is now pointless, though, as I've realized that such a thing is very non RESTful (thanks to you). – Jacoscaz Jan 25 '14 at 19:16
  • One media type contains a representation with metadata, the other without. There's nothing unrestful about that. – Pedro Werneck Jan 25 '14 at 19:39