{
book: {
id:1,
name:"To Kill a Mocking Bird",
author_id:2
}
}
How do you get more info on the author if you only have this piece of information? Rails/ActiveResource guesses through convention: "/authors/2", but that might not be the case, which makes this approach very brittle.A better more "RESTful" approach might be:
{
book: {
href:"/books/1",
name:"To Kill a Mocking Bird",
author: {
href:"/authors/2"
}
}
}
The REST client would then be able to traverse the representation without making guesses at the URL, and if the end-point of '/authors:id' changes for whatever reason, the href would be updated accordingly.Pagination/large data-sets could be solved as well:
{
books: [
href:"/books/1",
name:"To Kill a Mocking Bird",
author: {
href:"/authors/2"
}
}
],
rel: {
prev: "/books?page=1",
next:"/books?page=3"
}
}
... and a bajillion other common RESTful API problems through better convention.I'd agree with the author that REST is misunderstood, but my opinion is that its misunderstood on the grounds that today's "REST" implementations are lame database serializations. The web has been doing this since the <a href/> tag was conceived, but for some reason, modern REST implementations left this out.
$ curl https://api.github.com/repos/github/gollum/issues -i
HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://api.github.com/repos/github/gollum/issues?page=2>; rel="next", <https://api.github.com/repos/github/gollum/issues?page=3>; rel="last"It's sad that it didn't happen in XHTML2, and also removed from HTML5.
If you say "erb", please don't be offended by me laughing.
Content-Type: application/vnd.acme-json-with-paged-hrefs
that means that all "href" properties are URIs that may be paged by appending "?page=NNN" to them. If both server and the client understand this content-type, the representation may omit the "rel:" part from the parent example altogether.Constructing arbitrary URIs by the client is not RESTful; however in this case it's the server-side that is in control of URI generation mechanism (it could serve a different representation, with a different Content-Type:, if it chooses to) -- thus it's perfectly valid from the REST point of view.
This is the same story as with the HTML <form> element. It also allows client to construct URIs by the specific rules known to both sides -- because the rules are defined by the appropriate standards about text/html.
But to the extent that they are all "lame database serialization" layers, I'd have to say "well - ya". REST is kind of just that.
I think that what you're really trying to say is that implementations you have found don't do HATEOAS.
I'm designing the API for Poll Everywhere right now. Internally a multiple choice poll resource consists of several database tables and Rails models, but I simplified the externally facing JSON representation down to:
{
multiple_choice_poll: {
title: "Fav color?",
options: ["Red", "Blue", "Green"],
sms_enabled: true
}
}
Had I followed Rails REST conventions, I'd have an overly complicated chunk of JSON.I'd love to implement a full HATEOAS stack on Ruby/Rails; we'll see if I get around to it.
---
BTW In case anybody needs to Google HATEOAS (like I did): http://en.wikipedia.org/wiki/HATEOAS
> A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.
http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch...
If a book is added, the page=x resource is simply outdated and should be refreshed.
I'm pretty sure users like their "Download as CSV" links, which I've generally done as /normal/resource/url(.csv)
While this post sets out the ideals, I think there are some cases where for usability, you have to do something less than ideal.
The web has grown organically and it has the warts to prove it. It's useful to think about the spec and to work toward improvements, but if it's real world possible to have your services work well for mobile clients on m.domain.com and real world impractical to do so on your main domain (or any of the other examples regarding actions, languages, versioning, whatever)—then by all means, break the rules.
I don't know if any browser will implement this or has implemented it, but in real world scenarios we'll probably have to stick with .csv and en/foo or ?locale=en for a couple of years...
Sadly no. Browsers suck ungodly amounts of dicks in their handling (or absence thereof) of the Accept header. I don't know of any web browser with an even remotely useful behavior on that one.
In practise no one does use it, so just forget about it.
/networks/
/networks/girl_talk/
/networks/girl_talk/tracks/
/search?term=bass&sort=artist
He argued for URLs like this (note the pluralization): /networks/
/network/girl_talk/
/network/girl_talk/tracks/
/search/bass/sort/artist/
My case boiled down to, “A URL represents the path to a resource. You should be able to remove any number of parts from the end of a URL and be left with a different, meaningful URL. In the case of search, the terms are options that describe what you want returned by the search, not resources.”His case boiled down to, “A URL is a sentence. You should be able to read a URL as English and get a good idea of what it represents. In the case of search, adding more path components adds words to the sentence to make the search more specific.”
He pointed out (paraphrasing) that URLs are a language — and languages evolve. URLs as paths better embodies the RFC, but a new style of URL might be more meaningful on today’s (and tomorrow’s) web.
In the search case, I think your coworker is wrong, since that would mean you have to construct URLs by 'hand', which violates HATEOAS. GET or POST parameters should be used to avoid that.
/search/bass/sort/artist/
That doesn't look like a hierarchical resource. You probably don't list sort options under /search/bass/sort/, and even then /search/bass/sort/artist/ wouldn't be logical subset of that.This URL looks more like a different view on /search/bass resource, so /search/bass?sort=artist is IMHO more appropriate.
/search/ would be an empty search, and for the sake of argument let us say that it returns the entire collection.
/search/?query=bass
This would restrict the collection to return only records that contain the word "bass". Based on the way that URLs are defined, these are considered separate resources.
The same with this URL:
/search/?query=bass&page=10
This is a different resource than the previous. In this case, sometimes it feels like the page should be a member of the search collection. It's up to you whether you prefer a URL like this
/search/pages/10?query=bass
In my head that is incorrect because to me the query string manipulates the last item in the hierarchy which is "pages/10". So the order of operations would look like this:
1. Select the first page from the search collection 2. return only items on the first page that contain the word "bass"
Developers will use either, just do it and provide documentation and be done with it
It's good to know about REST so you can use it where it makes sense. But at the end of the day, doing what is right for your app trumps following any given methodology.
However, Mark created a service called "Is It RESTful?" (http://isitrestful.com/) to deal with all the engineers asking him that question :)
REST doesn't really care about pretty URIs either, in fact one truism about REST is that people who spend a lot of time worrying about pretty URIs are probably missing the more important aspects of REST.
Oh and I agree with you, people can spend a long time coming up with pretty and hackable URIs and in my experience clients often just don't care (sometimes its worth the effort though).
However, I do have a problem with REST that I've been dealing with lately. Specifically, the question of web-hooks. Many services today allow you to pass a URL that they will hit with a POST request whenever something happens. A good example is the GitHub post-receive hook (http://help.github.com/post-receive-hooks/). So, to be a good student of REST, I create an /update resource for the POST (similar to the /transaction example from the article). However, /updates might come in a variety of formats. Not just JSON vs XML, but GitHub vs Gitorious vs Beanstalk vs etc.
So, how do I handle these "formats". Presumably the "Accept" header is out of the question (unless the provider happened to know about MIME's vendor extensions and used them). So then is it acceptable to add a parameter? Use "/update?from=GitHub" for example? Or, is it appropriate to use an extra path element like "/update/GitHub", since the resource really is a "GitHub update", not just a vanilla "update"?
If where the update comes from would be stored as an attribute (i.e. column in the table), use the parameter option (/update?from=GitHub). If, however, they'd be separate types of updates (i.e. separate tables), use the separate URIs (/update/github or /github_update).
This is an analogy, of course, as there's no need for a 1-to-1 resource-persistance mapping, but it's a useful way of thinking about it, I think.
Keep in mind what the R in REST stands for. Each resource is a representation of internal data. You can have multiple representations under different URLs even though they're powered by the same internal data structure. Ideally you'd use the Accept header to do it but sometimes you need to be practical.
The concept of internal data structure doesn't enter the picture at all; for all the client knows, the response might even be generated by a monkey typing on a keyboard.
So if you're using different URLs, you're saying that those are different resources, not multiple representations of the same resource.
Sure, it may be useful and 'practicality beats purity', but it's bending the concept.
False. Each resource is a resource. The representation and the resource are completely independent.
Does anyone else see a diminishing return on pedantically following the REST-prescribed design and actually creating an API that people are familiar with out of the gate? I feel like if I followed this article to the T in my current design, anyone trying to integrate with it would spend so much time reading my API documentation just to figure out why they weren't getting an XML reply that it would stop being productive.
I am working on an API for imgscalr right now and I think I have it about 80% RESTful at the moment -- the parts I'm not doing is paying any attention to the headers either coming or going between client or server.
I'm using the more recent "classic" /path/object.{format}?arguments format that I have seen folks like Wordnik and Vimeo use.
It may not be purely RESTful, but it is intuitive and I can't help but think: "Remember 3-4 years ago when REST wasn't all the craze and no one knew what it was? The web still managed to function back then..."
I'm trying to mix some practicality in a bowl filled with "best practices" and come up with something that most people can stomach.
I hope I hit that mark, but we'll see. As far as I'm concerned I'm sticking with the versioned URLs because I find it more intuitive for endpoints that change, get renamed or are removed than slamming one inside of a mime type or header or even a query string param a la AWS.
the biggest issue with the rest-wanna-be interfaces is their use of object ids instead of object uris. so that I have to construct my own urls to access stuff.
in a proper restful api you are NEVER supposed to construct your own url. you are supposed to get all the relevant ones from the service.
and this kind of api is actually much more user friendly and allows for much better discovery. you just get the single top api url which has references for all the available collections objects and operations right there in the result.
So something like:
GET /image.json/pig.png?size=150x100
as opposed to GET /image.json?id=pig.png&size=150x100
where the arguments specific to the noun (or object/entity or image resource in this specific case) go in the query string, but the URL stem itself must be a valid resource reference?Thanks!
This makes things really confusing when people talk about REST because you can't really know what they mean by it.
1. I'm an old Web programmer, and my introduction to the Web started with HTML, not HTTP. I don't just write APIs, I write Web apps. I find it difficult to explain to people what this means:
<form action="/some/noun" method="POST">
If you are religiously RESTful, you probably think this is fine. But I'm a religious English reader. When I see the word "action", I think of a verb, not a noun. When I see the word "method", I think of "how", not "what". So when I look at the HTTP spec, all the HTTP "verb"s look to me like how-I-should-do-something, instead of what-to-do, and the resources (URLs) look to me like the what-to-do, instead of what-they-represent.Small semantics issues I suppose, but here's another one:
2. HTTP is not a programming language, and yet it demands a (very) finite set of actions and an infinite set of objects to model the real world, where there are an infinite number of actions and objects. What I mean is, in Java or whatever OOP language, I can define classes to model objects and define methods in classes to model actions on objects, but I'm not sure if I can do it pragmatically in HTTP without getting yelled at.
3. HTTP statuses. Almost the same problem as the above. I have many different kinds of statuses, not all of them fit in the finite set of HTTP statuses, and they don't always provide the granularity I want. Can I return a non-standard status number? How would the clients behave? I have no idea.
4. Being RESTful means not being stateful. But you see, there's this thing called session and login cookies and many other tracking cookies that I have to take care of. Again, I don't just write APIs, I write Web apps. I would like to not do multiple handshake requests just because a paper says I should. I would also like to not get yelled at when I decide not to.
5. HTTP is RESTful, thus HTTP is REST. Please don't tell me HTTP is the best we can do. Can I have something more minimalist, extensible and powerful enough to model the real world?
-- A troubled Web dev.
- HTTP is a protocol.
- HTML is a markup lanaguage.
- REST is an architectural model for building web services.
They are all different.
> HTTP is not a programming language.. > HTTP statuses > REST is stateless
HTTP is a protocol. A protocol by definition allows certain constructs and prohibits others. There are books available for modeling real-world problems with REST, such as RESTful web services cookbook. I'd suggest going through them, before declaring REST is impractical.
>I'm not sure if I can do it pragmatically in HTTP without getting yelled at
You can certainly use HTTP as you like it, just please don't call it RESTful unless it actually is. A lot of web APIs are not RESTful, nothing wrong with that.
> don't tell me HTTP is the best we can do..
Unfortunately it is for now. Everybody is free to invent their own protocol, write production quality servers to implement it, and get everybody else to adopt it.
2) Well, there's HTTP and there's REST, they're related but no the same. HTTP is a full protocol, completely defined; you can't add more verbs, period.
REST is an architectural style. It has a series of constraints, and it tells you that if your system architecture complies to them, it'll have some useful properties, like low coupling and such. HTTP is just an example of a RESTful architecture.
Now, if you're designing an architecture and you want to follow REST, you can choose the verbs you want, but these should be generalist and not tied to specific names. This provides an Uniform Interface, which simplifies and decouples the the architecture.
3) See above. HTTP statuses are fixed, you can't return other stuff. If you're designing your own architecture, you can use whatever you want. Hell, you can return different pictures of kitties for each status if you want to.
4) As the Zen of Python states, practicality beats purity. But you should be aware that by adding state to the connection, you'll lose some advantages. Let's say the user is performing a multiple step action, and the server he's using breaks. If the server was holding the state, now the user has lost all the work and he'll be pissed at you. If on the other hand, the state was saved by either the client, or more "RESTfully", by the mere fact that he was on a specific URL, than any other server can pick up where the other left without annoying the user.
5) Sure. We just need to rewrite all the browsers and servers worldwide, including a bunch of embedded ones that can't be reflashed. It's possible...
Because according to the spec, each resource is named by a single URL, so two URLs name two different resources. But if you put version numbers in the URL, you might end up with http://example.org/v1/rubyrescue and http://example.org/v2/rubyrescue, which according to the spec are two different users but in reality they're the same.
>also a v1 user really might not be the same as a v2 user
In what cases should the users be tied to the API version? I can't think of any.
I don't think this is technically correct. For instance, you might have a blog with a post at /blog/2011/07/03/why-i-love-rest and you might have /blog/current represent the same resource until you post something new. This seems like a valid case in which two different URIs name the same resource.
If you are versioning the resources themselves I think the version in the URI is perfectly fine. In reality this is almost never the case and people mainly use the version in the URI to designate different versions of the representation. This is bad since it ties the URI to the representation which is a big no-no.
I guess my point is that if i have to pick, i'd rather occasionally have two request urls with a minor version difference that are actually the same resource than two urls that appear to be the same resource but are not because one was requested with a header that affects the returned data.
It's not saying various practices are "bad," but that they don't conform to REST or the principles laid out in the HTTP specs.
Frankly, I don't give a damn about the REST spec, and neither should you. When I see an API I want it to be simple and clear.
/getAllPages/
Hey, it's a verb and I've got a pretty good idea of what I'm going to get back
/getAllPageNames/returnType/JSON
Now I really know what I'm getting. The simplicity and usability of this structure absolutely trumps a spec compliant call that involves request headers and nouns.
If you're building a system that requires having read someones dissertation, you're not doing us any favors. Especially when it comes to an API. Keep it simple, stupid.
Remember that your understanding of what a URL 'is' or 'should be' comes from a great deal of technical experience. If you're not working day in and day out to make powerful tools accessible to people WITHOUT such experience, please stop programming. Really, get out of the pool. Whatever awesome knowledge you need to make a system work internally is invaluable, but your interfaces should make the world a simpler, more magical place.
I did not downvote you but the REST architecture is well thought out, simple to follow, and very sufficient if you are moving content over HTTP.
http://www.mywebsite.com/api/getAllPageNames/returnType/JSON
In this string 'get' appears once. However, as an experienced dev, you know that this is a GET request. To you it looks redundant. However to someone trying to understand what will happen when they hit enter with this URL in their location bar it is meaningful.
The question at that point is naturally "But if you don't know that's a GET request then why are you using an API?"
This is the point I'm driving at. There are scores of underserved individuals who want to do interesting things with your website that go beyond your GUI, and they are just brave enough to read through your API docs.
Now, when I'm thinking about API design I have a big initial choice. Is this API for skilled developers who care about the REST spec? Or is this a tool for as many people as possible to get more out of my service than I have time to accommodate with features. This is where I will always say "I don't care about the spec." A really talented dev will read the docs, discover how my design works, and will write something cool on top of it. I can trust the hackers I know to make things work by hook or by crook. The same cannot be said for someone who really wants to extend my functionality but isn't a talented developer.
I feel it's my responsibility to produce a tool that can be used by as many people as possible. I don't want to make a high-end professional camera, I want to make a better point and shoot. I want to extend the abilities of people, not demand they gain a large skillset to use my new tool.
New programmers and enthusiastic users are always on my mind. These are the people who's preconceptions are that it should 'just work' and that if it doesn't it's my fault.
This is why I applaud decisions like Chrome dropping http:// It simply doesn't matter to 99% of the users of the product, and in fact makes browsers less friendly and more confusing.
If I can get my api to work like this, then I will:
'I want to see all the names of pages on mywebsite.com'
If I had access to a deterministic natural language parser then I'd use it. As such a thing doesn't yet exist, I try to remain as true to that ideal as possible.
The REST architecture may be less confusing than others, but it is far from simple.
Generally works better for more real entities like for example specific products, than for articles.
It was back when early versions of Struts were 'the designated alternative', and in the bad old days of J2EE and JAX-RPC.
Then Java EE 5 came out, which solved large chunks of the pain that J2EE inflicted, JAX-RPC got replaced with the infinitely better JAX-WS and there was a new breed of web frameworks as well, which blew Struts out of the water.
About that time REST essentially became 'yesterdays technology, solving yesterdays problems'.
I find it interesting that the guy banging the REST drum is a Ruby fan. Has REST always been part of Rails? Or is it something that has crept in over the last couple of years?
Is there anything genuinely new here, or is it the same old story, some dude clinging desperately to an obsolete technology?
I just question the concept that REST is in anyway considered to be obsolete within the Java web world. Spring-MVC focuses more and more around this technology, and is also the delivery point for REST web services from spring; Struts 2 has slowly moved more towards RESTfulness; and additionally frameworks like Play have come around.
'...REST always been a part of rails?' '...obsolete technology'
How is REST -- a set of architectural principles and constraints -- obsolete when you use it every time you browse to a web page? I feel people need to start treating REST more for what it is rather than an API or some library, or SOAP for that matter.
> Accept: application/vnd.steveklabnik-v2+json
This declaration loses information, because it no longer contains the MIME type for JSON in a standardized format. Assuming the server responds with the same string for Content-Type, any application that does not know specifically about this API can no longer recognize that it's JSON and, e.g., pretty-print it for a user, as I haven't seen done for JSON but is regularly done for XML by browsers.
On the other hand, the original suggestion:
> Accept: application/json
works in theory, but in practice makes it more difficult to test the API in a browser. This is not the end of the world, but there does not seem to be any real benefit in using Accept. I cannot think of any practical situation where a tool can use the standardized header for an advantage...
I've found this a nice addition to documentation and, depending on how well the HTML representation has been done, is great for learning/exploring an API.
Remember that one of the advantages of URLs is the ability to easily share them, however I'm not sure I'd be comfortable sharing content that could show up translated to some recipients, based on the language of their browser/application/computer. For example, most CMS systems assume that the content can be completely different between languages (for the same article): you can have the full text in English and only a teaser in other languages.
Maybe not a pure REST approach but using '/en','/pt','/fr' in the URL has proven to be much easier and safer, from my experience.
On that topic, to rely on an 'Accept' header is pretty risky. That presumes the client will always have control over the headers. It is in my opinion always wiser to make the API determine mime type by extension (.html, .xml, .json etc).
We need to keep our priorities straight.
"A big problem with REST is that it is NOT a canonical (or even important) standard, but rather a useful pattern than can be used to make things exposed via HTTP more intuitive."
No, its not meant to make HTTP interfaces "more intuitive". HTTP clients are machines. They don't have intuition. When your web browser hits the HN front page, it isn't using intuition to figure out what links to display.
You can make an argument that for a particular web service, adhering to a particular principle of REST doesn't matter. But you have suggested that the principles of rest never need to be an important consideration for any web service, which I submit is plainly false.
Most web developers aren't going to read the computer science papers about REST, and how strictly you want to adhere to it, depends on you, and your development team. It's a design pattern, or a tool, but it's not a religion.
On that note, I've gone into several job interviews where they ask me to explain what REST is, and I always start with, "REST stands for Representational State Transfer...", at which point, I get the feeling that the interviewer wasn't aware of that, and I wind up telling them way more about REST than I think they wanted to know.
i) most successful "RESTful" APIs don't really follow all the REST principles (e.g Flickr, Amazon, Dropbox). My thumb rule is this: If an API does not start from a "mother" URI that gives you the most updated list of resources that can then be requested by the application, it is not really HATEOAS.
ii) a purely resource-oriented view of your entire API space shoehorns you into doing really strange things to keep REST "purity"
So my conclusion is that using an architecture/concept originally intended for humans navigating hypermedia documents may not be a natural fit for parts of your API that cannot be modeled as such. See the Dropbox REST API documentation (http://www.dropbox.com/developers/docs#api-specification) (" Section: Deviations From Standard REST Style") to see an example of the pragmatic decisions taken.
One thing that I cannot find mentioned neither in the article nor in comments, is the confusion related to the idea of state.
While REST is, by definition, stateless, it merely describes the session, not the manipulated data. There's no way to avoid, at least implicit, object's state. For example, if user's password is not empty, it means that the user already set the password.
More comprehensively, with /users/1/edit, or whatever, it is frequently expected to get a different validation error, depending on the flow, such as a paid account might require more billing related details than one without email confirmed.
Of course, it is a nightmare to maintain such matters implicitly. That's why Ruby on Rails plugins like acts_as_machine, and similar, come handy. They do provide an explicit description of the object's behaviour, easy to transform into documentation, depending on the current state.
The idea shows its full potential with multipage forms. Each step of the form might be described with a different state, stored in the state attribute, leaving the controller RESTful, and the model's validations easy to understand.
A yet another confusion comes with too close database mapping. To stick with Ruby on Rails, there is nothing preventing the developer from creating his own setters and getters, like def vattr=(); end; def vattrr(); end.
The framework passes the value of a virtual attribute, using params, to #update_attribute, and other methods, the same way it does for regular attributes created automatically from the database's schema.
Very frequently such attribute provides a much cleaner way to represent the model, rendering either the HTML or the API much more easier to write or understand.
1) Representing all resources with noun - We had a tough time representing all resources with Noun. One of our APIs is Post on \PrintJobs\ - creates a new print job
But printing can only start when all the data (content to be printed) is uploaded on the server. So client needed an API to tell the server that it can start printing..something like this..
\printjobs\1\print \printjobs\1\cancel
one way we thought to avoid this was to have a represent it job state and client can change them like this..
\printjobs\1 Put : <job> <state="print"> </job>
But there are cons
1. These were not actually states, these were actions(verbs)..because state would be initialized, printing etc.. so if client does Get after making it Put..it will get "printing" not "Print".
So we were tangling with keeping semantics clear and making it easy at the same time. Hence we went with these resources. Do you think it could modeled better?
2) When we think of versioning, we always assume that only the representation can be changed..why not behavior? Take for e.g. if api implementation changes but not representation..clients may be dependent upon the implementation (i know this is bad! since implementation details are getting leaked out from the API)
Thoughts?
It is essential that RESTful applications be able to evolve independently from the client. To allow this, they must use forms of hypermedia generic enough to serve as the engine for all present and future versions of the application. If the client has any code specific to your app, then your app is not RESTful in any scope beyond its own.
I'm not convinced that the whole resource vs action thing is all that important to REST. It's an ideal that has been largely ignored in practice and the web has been quite successful without it. Contrast this with HATEOAS which has been the unavoidable reality of the web since day one.
No matter your thoughts on REST, it's dead. It's never happening. This argument has gone nowhere for 10 years.
Very few if any websites conform to the spec, and browsers have made it impossible to do so.