Skip to content

Instantly share code, notes, and snippets.

@andreineculau
Created May 9, 2012 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreineculau/2647886 to your computer and use it in GitHub Desktop.
Save andreineculau/2647886 to your computer and use it in GitHub Desktop.
REST: filtering
If you have
/cars
/cars/{carId}
/individuals
/individuals/{individualId}
and then
/individuals/andrei
needs to link to my cars, which would be /cars?individual=andrei
(( side-tracking here: maybe http://api.garage.com/cars?individual=http://api.garage.com/individuals/andrei seems better since the URIs are the IDs ? wdyt? ))
Question is, would you have a link like
#1 {rel:'owned-cars', href:'/cars?individual=andrei'}
#2 {rel:'owned-cars' href:'/cars'}
#3 {rel:'cars' href:'/cars'}
Say that both cars and owned-cars support more filtering like "boughtAfter=YYYY-MM-DD", then what is the purpose of "hardcoding" individual=andrei, if the client has knowledge about the relationship's query parameters?
I vote for #3, just because in this situation the rel owned-cars is not much different than "cars that relate to this individual".
What's your take?
PS: Per mentioned that the query parameters would be specified by the resource, but the client doesn't care about that. It only has media-types and rels, among which rel is the only one left to specify those.
@permelin
Copy link

permelin commented May 9, 2012

Regarding 'cars' vs 'owned-cars' you could:

A. Let "owned" be implied, as per #3.

B. Or, specify it in the rel, as per #2 and #3.

C. Or, specify it by context:

<individual>
    <owned>
        <link rel="cars" href="/cars?individual=andrei">
        <link rel="airplanes" href="/airplanes?individual=andrei">
    </owned>
    <wants>
        <link rel="cars" href="/cars?individual=andrei&collection=wishlist">
    </wants>
</individual>

D. Or, why not:

<individual>
    <cars href="/cars?individual=andrei">
        <link rel="wants" href="/cars?individual=andrei&collection=wishlist">
        <link rel="for-sale" href="/cars?individual=andrei&filter=selling">
    </cars>
    <airplanes href="/airplanes?individual=andrei" />
</individual>

@permelin
Copy link

permelin commented May 9, 2012

I strongly prefer "/cars?individual=andrei" over just "/cars" because it is easier for the client, and it follow the principle of least astonishment.

It is "here is the URL for the collection" vs "here is the URL to the resource that lets you search for the collection."

@permelin
Copy link

permelin commented May 9, 2012

Are you by the way saying that a media type cannot specify the query parameters for a resource?

@andreineculau
Copy link
Author

Well, yes I'm saying that. The media type specifies syntax and semantics. I find it weird to read: go to URI x, with Accept: text/html and be aware that text/html means that you can add a query param x,y,z. What do you think?

PS: I realized I might be biased due to the documentation-process for preferring just /cars over /cars?individual=andrei. Will sleep on it

@permelin
Copy link

Obviously a generic type like text/html must be open to any type of transport or access. But take application/atom+xml;type=feed for example. If I understand the specification correctly it (unless otherwise specified) accepts POSTs of new entries (if you are authorized). Now you have moved beyond syntax and semantics.

If you want to split hairs you can discuss whether it is the media type of the collection or the link to the collection that has the contract of "it is OK to POST", and maybe it is indeed the link. For a protocol like AtomPub that distinction may be important, for a company specific API that no one else is ever going to implement a server for, it may not be.

It probably makes more sense to let the relation specify things like this, and query parameters. But then I don't know if rel="cars" is enough. How do you distinguish that from a cars collection resource that does not support queries?

@andreineculau
Copy link
Author

The examples that you gave put ever more ants in my brain.. you mentioned "context" as in "subcontext". Previously I have considered the context being one and only one = the current resource. A collection resource should link to its items, nothing more, nothing less. I don't go to a collection resource (aggregated or not) expecting to find links on how to do changes 3 levels deep into the structure
eg. I go to /cars and get links to a resource the individual who is a neighbour of an owner of a car (nested structure)

Same way, i see your C/D example being more like:

/individiual/andrei
{
 name: 'andrei',
 links: [
  {rel: 'cars', href='/cars?individual=andrei'},
  {rel: 'airplanes', href='/airplanes?individual=andrei'}
  {rel: 'cars-for-sale', href: '/cars?individual=andrei&status=sale'}
 ]
}

and then the client has rel information that it can also go to
/cars?individual=andrei&fabricationYear=2000 from a cars rel
/cars?individual=andrei&status=sale&fabricationYear=2000 from a cars-for-sale rel

@andreineculau
Copy link
Author

(o.O) no realtime updates in gist

Personally I don't think I would separate between a rel=cars that you can filter and that you cannot filter on.
Based on the context, on the authorization, etc some or all query params might be allowed or not.
The same way I don't separate between a mediatype that will allow the client to set or not a field.

@andreineculau
Copy link
Author

Struggling with these rels. If there's anything about REST design that makes me wanna go pragmatic, it's rels.

How do you update a relationship between two resources?

Say
/individual/andrei <--------> /cars/123
/individual/andrei has a "current car" /cars/123
the API client will find a link in "andrei" to do a GET on car "123"
BUT the API client cannot do a POST on car "123" to update the current his current car (or else that car might be a car that per has in his garage as well)
The API would need to do a POST on "/individual/andrei/current-car" in order to e.g. change the paint color..

But then do you have 2 links with 2 rels like
GET /cars/123; rel=current-car
POST /individual/andrei/current-car; rel=edit-current-car

or do you just think of the current-car as a different resource altogether than a car, and end up with the same "content" in 2 places
GET/POST /individual/andrei/car; rel=current-car ((( the GET would return or maybe redirect altogether to /cars/123 ))) ?

@andreineculau
Copy link
Author

If you consider the first option I gave, with current-car and edit-current-car,
when you do a POST to edit the current car, a new car ID will be created, which means that "andrei" will link to car "456" now, so the API client also needs to do a GET on "andrei", to update its links.
Am I going nuts here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment