Pagination in a REST web application
I agree with Fionn, but I'll go one step further and say that to me the Page is not a resource, it's a property of the request. That makes me chose option 1 query string only. It just feels right. I really like how the Twitter API is structured restfully. Not too simple, not too complicated, well documented. For better or worse it's my "go to" design when I am on the fence on doing something one way versus another.
I think the problem with version 3 is more a "point of view" problem - do you see the page as the resource or the products on the page.
If you see the page as the resource it is a perfectly fine solution, since the query for page 2 will always yield page 2.
But if you see the products on the page as the resource you have the problem that the products on page 2 might change (old products deleted, or whatever), in this case the URI is not always returning the same resource(s).
E.g. A customer stores a link to the product list page X, next time the link is opened the product in question might no longer be on page X.
HTTP has great Range header which is suitable for pagination too. You may send
Range: pages=1
to have only first page. That may force you to rethink what is a page. Maybe client wants a different range of items. Range header also works to declare an order:
Range: products-by-date=2009_03_27-
to get all products newer than that date or
Range: products-by-date=0-2009_11_30
to get all products older than that date. '0' is probably not best solution, but RFC seems to want something for range start. There may be HTTP parsers deployed which wouldn't parse units=-range_end.
If headers is not an (acceptable) option, i reckon first solution (all in query string) is a way to deal with pages. But please, normalize query strings (sort (key=value) pairs in alphabet order). This solves "?a=1&b=x" and "?b=x&a=1" differentiation problem.
Option 1 seems the best, to the extent that your application views pagination as a technique for producing a different view of the same resource.
Having said that, the URL scheme is relatively insignificant. If you are designing your application to be hypertext-driven (as all REST applications must be by definition), then your client will not be constructing any URIs on its own. Instead, your application will be giving the links to the client and the client will follow them.
One kind of link your client can provide is a pagination link.
The pleasant side-effect of all of this is that even if you change your mind about pagination URI structure and implement something totally different next week, your clients can continue working without any modification whatsoever.
I have always used the style of option 1. Caching has not been a concern since the data changes frequently anyway in my case. If you allow the size of the page to be configurable then again the data can't be cached.
I don't find the url hard to remember or unclean. To me this is a fine use of query parameters. The resource is clearly a list of products and the query params are just telling how you want the list displayed - sorted and which page.