
The RESTful CookBook - bencevans
http://restcookbook.com/
======
GhotiFish
<http://restcookbook.com/Resources/pagination/>

    
    
       "Even though it's tempting to create your own pagination scheme by "building" 
        URLs, you should only use the information given by the API. This means, you 
        cannot assume that the 3rd page can be found at /collection/3. If you do, 
        your client will break as soon as the API changes its pagination behaviour."
    

Is that a legitimate caveat?

Are there clients that don't break when you change the API the client works
with? Pretty smart clients.

~~~
buro9
Two things:

1) Yes, you should only use info supplied by the API. This should mean that
the API is helping to ensure the client never sends the user down a UX dead-
end, and also that the client does not break when the API changes.

But...

2) I don't like the thought of collections having a resource identifier for a
page. As items are deleted from the collection, the resource identifiers now
represent a modified resource and break caching (delete item 3 of a 5 item per
page collection, and all resources in the collection - logical pages - have
been modified implicitly).

I much prefer using query string for this, as it is a query on a collection.

But... the API should still be the thing that generates/builds these URLs, the
client should never do this work. The client must use the provided
first|prev|self|next|last URLs, otherwise the client may break in the future.

An example of how I prefer pagination:

    
    
        "collectionName": {
          "total": 861,
          "limit": 10,
          "offset": 100,
          "pages": 87,
          "links": [
            {"rel": "first", "href": "/api/things?limit=10"},
            {"rel": "prev", "href": "/api/things?limit=10&offset=90"},
            {"rel": "self", "href": "/api/things?limit=10&offset=100"},
            {"rel": "next", "href": "/api/things?limit=10&offset=110"},
            {"rel": "last", "href": "/api/things?limit=10&offset=860"},
          ],
          "items": [
            ...
          ]
        }
    

Where 'limit' and 'offset' are provided by the query string (but default to 25
and 0 respectively) and the API takes care of generating valid links (like not
including 'prev' if you are on the first page').

This way the client does what it should, just use the links provided.

And whilst I'm here... one of the things I dislike about link relations is how
they presently fail to mention the method you should use (let alone content-
types acceptable by that end-point).

In the example above every link is a GET, in the example on this page
<http://restcookbook.com/Basics/hateoas/> they're probably POST. In the link
relation assignments [http://www.iana.org/assignments/link-relations/link-
relation...](http://www.iana.org/assignments/link-relations/link-
relations.xml) 'edit' is probably a PUT. There's an 'edit', but not a
'delete', so it's not as if just sending more than one 'rel' might describe
the method.

Today the audience of an API is a developer, so it's fine to just point them
at the documentation. But tomorrow it may well be a computer.

~~~
MichaelGG
So what if you want to have a list of pages to jump to - send back 80 links?

What is a client supposed to do when a new "nextToLast" appears? I've yet to
hear of any API consumer that is driven like a browser.

What's the actual point, other than some purity to some abstract concept? Just
make it part of the API to take /api/things?page=x and do the right thing.

What's "tomorrow it may well be a computer" supposed to mean? We'll have AI?
Or there will be some sort of new WSDL "... for REST" invented?

~~~
steveklabnik
> What's the actual point, other than some purity to some abstract concept?

The actual point is decoupling. It's generally considered in software
architecture that design that's decoupled is a little harder to build upfront,
but survives change over time.

As a 'real life' example, because Twitter exposed internal details (a tweet
ID), clients sorted based on that number, because they assumed it'd be
monotonically increasing. Once sequential IDs became a problem with Twitter at
scale, they had an issue: if they switched to GUIDs, clients would break,
because they were sorting based on the ID value. They had to invent an
entirely new algorithm (Snowflake) to adapt to this change. This wouldn't have
happened if they hadn't leaked internal details. It's basic encapsulation.

~~~
MichaelGG
I'm not sure how the Twitter example is remotely related to what I'm asking.
You're saying that if Twitter returned long URLs as opaque tokens to get, then
it'd have been ok. Sure, but it'd have been fine if they had made the tweet id
an opaque token either way. Surely returning named URL pairs isn't "basic
encapsulation", and "GET /Tweet/<token>" has no reason to break.

I can see how returning hypermedia adds yet another layer of abstraction (and
potentially plenty more round trips!). I'm just unsure how it helps. I don't
understand how actual client code (besides a browser) can deal with arbitrary
hypermedia. I'm cautious when I don't understand why people are hyped up about
something, but I've yet to see any "real life" examples that demonstrate real
benefits of this approach.

~~~
IanCal
I can't point to them because they're internal, but there are some good ones
I've used. Pagination was one useful part, where we saw the API change but
didn't have to change the client. A second was being able to explore parent
relationships, so we could start somewhere in the tree and move up until we
hit the level we were interested in.

There are always agreements between the API designers and client designers,
because the code isn't intelligent, so it doesn't know what 'parent' means. If
the name of that changes, then the client would have to change. What can be
different is the url structure to get the 'parent'. Maybe there's a new token
that has to be there, or the naming of something has been changed, or
whatever. Those changes can be made without breaking the clients. Putting this
in the responses means two things:

1) Small changes don't break everything (pagination is a great one, its a
/pages/1 one day then ?page=1, then ?offset=25, then ?pageSize is optional,
then it's required, etc.).

2) Fewer assumptions baked into the client. Getting the tweets for a user
you've loaded would be nicer as load(user.tweets) than
load("/tweets/"+user.id)

------
glitchdout
Cool idea. But it doesn't seem to be finished. Here's an example:
<http://restcookbook.com/Basics/loggingin/>

Maybe it wasn't the author that submitted this? Or is the author asking for
some help?

~~~
89vision
For me this is always the hardest part of REST. Do people use cookies for
this?

~~~
tom_b
I've chased the RESTful login/authentication around the web off and on when
thinking about REST apis. It _seems_ to boil down to two main approaches.

1 - follow the AWS API models, with a signed request using a private secret
known only to the user and the server-side. You can see the S3 docs on RESTful
auth using this approach. Also seems to recommend doing this over SSL.

2 - use SSL and send a userid/passwd or authentication key on each request.

In general, cookies are regarded as one of those "makes it not restful" type
things.

I'd love to hear from HN'ers on how they handle RESTful authentication,
particularly for projects where they are providing an API that is primarily
consumed by a web app or other tool they implemented for users and have used
RESTful api design as a design viewpoint.

~~~
philjackson
ApiAxle provides the first method with a hmac sha1 encoding of the current
epoch, secret key and api key.

<http://apiaxle.com/docs/signing-requests/>

------
weixiyen
Is my API RESTful when I use (only) JSON? NO.

There is no predefined way to deal with link discovery in JSON.

:(

~~~
rdtsc
It is kind of silly. Just add a reasonable convention and stick to it.
{'href':'<url>', 'rel':'<linktype'} or something like that. Saying to throw
away your JSON representation because you can't do links is ridiculous.

~~~
steveklabnik
Once you add extra stuff, it's not JSON any more. If you pick a convention,
document it, and then serve it as some other type ( like application/foo+json
) then you're good. It's true that there's no reason to throw away the
_serialization_ format that JSON provides you, but if you serve
application/json, then you can't have extra 'conventions.'

~~~
rdtsc
Presumably what you serve is not random JSON, it is already application
specific in some ways (unless it is proxying or encapsulating other services,
which is reasonable). So say there will already be conventions about how to
service collections (/carts/ that will be an array of objects that look a
certain way or or single items /carts/<carid>/ that is an individual shopping
cart may represented as a single json object with some known keys and values).
So having links and relationships is just another such convention isn't it?

How is linking now special in the sense that it can't be considered bona-fide
JSON, if it is parsed by a JSON parser without error just like a shopping cart
it.

Yeah I am not sure how important it is to say that I am serving
applicaiton/foo+json or just application/json? I have been doing just
application/json lately, I may very well be wrong about it.

~~~
icebraining
I'm a big REST fan, but I think using a different mediatype is only important
if the format is (or can become) generic and used by other services. For
example, if you're serving a GeoJSON document, which is a open format used by
many services, it makes sense to use a specific mediatype. If, on the other
hand, the format is totally custom to your service, I don't really see the
point, since the client parsing it must be custom too.

The only advantage I can see to using custom mediatypes is if you want to do
versioning (+v1, +v2, etc).

------
evv
<http://restcookbook.com/Basics/hateoas/> \- What is HATEOAS and why is it
important for my REST API?

This page doesn't even try to explain why HATEOAS is important. And I'm not
sure that it is.

This example uses some arbitrary xml to describe the API, but if no client can
consistently read and understand it, what purpose does it serve?

------
drdaeman
Many examples do not comply to HTTP standard at all, they're just schematic
sketches. I mean, required headers are missing, response bodies are not
separated from headers and so on.

I believe, examples must be as real-world as possible. Say, the PATCH example
must add at least an Content-Type header (and probably use RFC5261), otherwise
an important aspect's lost.

~~~
jaytaph
I think that's a good point. I will try and fix this, but the emphasis should
be on the point we're trying to make with the recipe.

~~~
drdaeman
I think, the important aspects could be highlighted. Although I'm not sure
Markdown allows, say, bold text chunks, in code blocks.

------
Hydraulix989
Spelling error on /Basics/hateoas/: "deposit" misspelled as "desposit" twice
in the second XML code listing.

~~~
jaytaph
Just fixed by a contributor. Thanks for the report!

