0

Let's say I have a resource /books, with a parameter ?author_id=. What should be returned if no author_id parameter is specified, e.g., /books as opposed to /books?author_id=42? Based partially on this answer, I have decided that if you hit /books?author_id=42 you will get an empty collection if author 42 has no books, instead of e.g., returning a 404.

However, in the case that client_id is null, I am not sure if I should treat this case the same way (i.e., the author with the ID of null has no books) or if it should be something like a 400, treating null as an invalid value for client_id.

Note also that books is a contrived example, and that in my case, I cannot simply return all "books" if the user hits /books. Assume it is a case that only the author has access to their books.

elethan
  • 16,408
  • 8
  • 64
  • 87
  • If the parameter is necessary the API should probably use a path parameter instead of a query one, IMO. In the end, the structure of the URI shouldn't matter for an application following the REST architecture as the intent is kept in the link-relation name. This allows the server to change URIs on the fly and clients still be able to invoke further actions. – Roman Vottner Jul 13 '18 at 16:34

3 Answers3

0

What should be returned if no author_id parameter is specified, e.g., /books as opposed to /books?author_id=42?

If the resource URL is valid /books, but server cannot serve this particular request then I will prefer HTTP 501 Not Implemented as response code. Because the server is responsible for not supporting this feature. This is debatable as some will prefer 4xx HTTP codes, but in my opinion 4xx error status codes points the finger at clients.

W3 Standard definition for HTTP 501

10.5.2 501 Not Implemented The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.

.

I have decided that if you hit /books?author_id=42 you will get an empty collection if author 42 has no books, instead of e.g., returning a 404.

This is absolutely fine.

Next question -

However, in the case that client_id is null, I am not sure if I should treat this case the same way (i.e., the author with the ID of null has no books) or if it should be something like a 400, treating null as an invalid value for client_id

This is fine too. As client is sending invalid id and it can be corrected from client side so 400 Bad Request is appropriate for this case.

Vinit
  • 2,540
  • 1
  • 15
  • 22
  • 501 should be used if the server in general does not support a HTTP method like i.e. `PATCH`. If only certain resources do not support an operation, i.e. `DELETE`, 405 should be returned instead if that operation is invoked on a resource that doesn't support it. If no representation for the resource could be found for the given URI a 404 is more appropriate as usually it is not the server's fault that the representation doesn't exist. – Roman Vottner Jul 13 '18 at 18:47
  • @RomanVottner -If the the server doesn't support `PATCH` then it should return HTTP `405 Method not allowed`. 4xx codes indicates that client is responsible for the error and client should fix it. 5xx codes indicates that server is responsible and same request will not work for client until server fixes it. lets say `/books` allows `GET, PUT` methods only and if client tries to use `PATCH`. Now if u return HTTP 501 then client will stop requesting but if u return HTTP 405 instead, then client can fix the issue by using `PUT` method. So 405 code is good when a specific http verb is not allowed – Vinit Jul 13 '18 at 20:21
  • Please, read through my comment once again and then also read through [this issue](https://github.com/sabre-io/dav/issues/101) or that [mailing list entry](http://sip-implementors.cs.columbia.narkive.com/GjYcZlgE/405-vs-501). Not every server (especially the old ones) might know what `PATCH` means. Instead of `PATCH` I also could have chosen a proprietary extension like [`LOCK`](https://tools.ietf.org/html/rfc4918#section-6.1) or what not. A client might also not be able to transform the request to an other method, i.e. when multiple resources need to be updated simultaneously – Roman Vottner Jul 13 '18 at 20:40
0

Basicly, it's up to you, how you want to handle this.

I developed some RESTful API's according to the Microsoft REST API Guidelines, which contains best practices.

According to the their guidelines, REST Clients have to expect, that collection data can be returned in page-sizes.

And if you provide paged results, you also want to provide filtering to big collection; so filter a collection with an author.

They use 'OData' styled filtering, sorting and paging. I'll quote the actual 'filtering' chapter:

The $filter querystring parameter allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with $filter is evaluated for each resource in the collection, and only items where the expression evaluates to true are included in the response. Resources for which the expression evaluates to false or to null, or which reference properties that are unavailable due to permissions, are omitted from the response (answer to your question: which means you should return an empty paging result)

Example: return all Products whose Price is less than $10.00

GET https://api.contoso.com/v1.0/products?$filter=price lt 10.00

The value of the $filter option is a Boolean expression.

Benjamin Schäublin
  • 1,526
  • 1
  • 16
  • 26
-1

First, in your example above, /books?author_id=42 is not restful imo (some religious discussion will no doubt occur). /books/42 would be "get me book with id=42". Instead, the API should take filter parameters from the body of the request as selection criteria. /books will include ALL books that match the embedded filtering criteria, null collection is a possibility.

If you want, the API can also check to see if some of the filtering criteria (author) is valid and return 404 if the author does not exist. That is an API decision, the UI just knows how to talk to it and handle the result.

Notice exactly what I predicted? Religious discussion along with downchecks. Read up on Roy Fielding's work and Leonard Richardson's elaboration.

John White
  • 705
  • 4
  • 12
  • What distinguishes whether a URI is RESTful or not? An URI (in its full length) is just a pointer to a single resource, nothing else! Further, a URI like `/a/b/c` doesn't state that `c` is a child of `b` or `a` a parent of `b`. This are just personal interpretations that don't need to be necessarily true! Applications following the REST architecture shouldn't further interpret URIs at all as this will break clients easily if the URI is ever changed, instead the link-relation name is the important thing about it actually. Further, this is a question targeting opinionated views -> close reason! – Roman Vottner Jul 13 '18 at 17:02
  • "Instead, the API should take filter parameters from the body of the request as selection criteria". This will break the basic REST principal, to have parameters in request body, you have to use POST method and as per standards, you should use POST method for creating resources. There can be exception to this, if search criteria is too complex, then yes for POST. But for this scenario we just have auther_id. – Vinit Jul 13 '18 at 18:00
  • @Vinit According to [the spec](https://tools.ietf.org/html/rfc7231#section-4.3.3) POST does not necessarily have to create a resource. The semantics are dependent on the implementation and therefore do not give any guarantees to clients. It is a swiss-army-knife which has to be used if the other operations don't fit. One might encode a JSON payload and put it into a query-parameter of a GET request. Which methods is better is debateble. One guarantees saftyness, idempotency and cacheability out of the box while the other does not give any guarantees at all but is more flexible in the end. – Roman Vottner Jul 13 '18 at 18:35
  • @RomanVottner My post above is based directly on the guiding principles of Roy Fielding who proposed the REST architecture in 2000 as part of his PhD. [Wiki](https://en.wikipedia.org/wiki/Representational_state_transfer). And according to THAT, "/a" is a collection of resource "a" while "/a/b" returns or modifies a single resource "a". There is no /a/b/c in REST – John White Jul 18 '18 at 20:29
  • @Vinit Yes, it could go in the URI but the OP stated he wanted to use authorid as "find all books for authorid". Since REST only covers retrieving a collection of a resource or a single resource, relational actions are "up to the user". As stated, it was my opinion (maybe I should have been clearer) that non-URI data should be in the body (I'm from the MVVM arena) so that is the logical place to look for further information. In the OP, /author/42 references an author with an id of 42. The body will say "include books". – John White Jul 18 '18 at 20:34
  • @RomanVottner I agree with you that a URI is just a pointer to an endpoint which will perform some action. Its the "standards" you adopt that determines its RESTful nature. I particularly like Leonard Richardson's work on the 3 levels of REST which includes HATEOAS. – John White Jul 18 '18 at 20:37
  • An URI like `/a/b` does not necessarly state that `b` is a child resource of `/a` by default. You are of course free to design such a construct. The important part however is, that a client should not deduct information from an URI itself but use meaningful (and given) link relation names instead as this allows servers to move resources arround without breaking clients. I don't like Richardsons maturity model at all. You can have level 3 and still not maintan a system that is compatible with REST; just think of an API that has typed resources or requires clients to have out-of-band knowledge – Roman Vottner Jul 18 '18 at 20:48
  • Note further: You only gain the benefits REST promises (i.e. freedom of APIs to evolve and change and making clients robust to changes) if you fully follow each necessary step. Only doing the stuff that is convenient will leave a coupling between client and API and thus lead to problems when the server-side is going to change. Therefore, everything before level 3 is not worth talking about in the context of REST IMO and even on making use of HATEOS (and therefore reaching level 3) there is still enough room left to still couple clients to the API – Roman Vottner Jul 18 '18 at 20:55
  • @RomanVottner I agree, /a/b does not invoke a relationship between two entities. In my example /a/b is a single entity with an identifer (b). Meaningful links etc are quite fine, I work with them a lot. Just pointing out that is not REST. That's one of the reasons I like HATEOAS, client doesn't need to know anything. Adds complexity though. – John White Jul 18 '18 at 20:59
  • @RomanVottner Agreed, as with any "standard", it is always possible to mess it up (and frequently occurs). It was apparent in the OP that he wasn't well-versed in REST so I KISSed. With you, we could have a great debate in depth :) – John White Jul 18 '18 at 21:02