REST Anti-Patterns (2008)
infoq.com
infoq.com
My favorite is when everything returns a 200, but the response is something like:
{
status: "fail",
error: "forbidden"
}
Sometimes they even include the 403 in the response, almost like the developer is giving you a giant middle finger.Also, these days, I think the blame is more likely lazy devs, poorly complying frameworks, or compromises to make things easier for some frontend library.
No, they really didn't. And I've started with Mosaic...
[1] Not to pick on retrofit -- it is generally awesome -- but http://square.github.io/retrofit/2.x/retrofit/retrofit2/Resp...
The status code was 200 but the HTTP body was literally "403: Forbidden". On an endpoint that was supposed to return XML .
I guess they just read the spec and assumed "the API returns a '403: Forbidden' " meant this.
You gotten a response that's HTTP 200, but the JSON itself contained something like "code: 403"?
Well, now I know what I'm going to do if I ever really hate my coworkers/company.
Wiki:
2xx Success
This class of status codes indicates the action requested by the client was received,
understood, accepted, and processed successfully
RFC 2616: 10.2.1 200 OK
The request has succeeded
Not really "proper" to use it that way, but if it works for you and your users I guess go for it. Also, I highly disagree with the rest of it (cleaner code, better interoperability, simpler debugging), but those are matters of opinion so there's no point in arguing them.How is this not processed successfully? The request was processed successfully by the webserver ... and the error was handled by the application, so you can reliably say it was processed successfully at that level, down to the CPU. Narrow interpretation to fit a narrative has no technical merit. That being said, standards are set with certain models in mind and are imperfect almost uniformly, so I don't put too much stock in adherence to what someone imagined or put through committee at some point. I do try to find the best way to iterate reliably with least astonishing abstractions and predictable interfaces. I reason about it in the terms of the standard and it serves my teams.
I guess google, facebook, microsoft and all the others are doing it wrong then? Or Improperly according to you? Because they do not respond with a 200 on application level errors in their APIs.
They made a choice to treat multiple applications as one. That's not what I would prefer and is less useful in my opinion. There are some CDNs and payment processors that are in operation, that use the 200 error response, so I tried it. I think it's clearly superior. YMMV
No, expressly in the HTTP spec, 5xx error codes are server errors. 4xx codes are all different kinds of application-level (usually resource-specific) errors.
2xx codes are full-stack success codes.
There's a load of early, popular, Stack Overflow questions that revolve around what status to return when, and how to actually return those codes in your language. For example, in ASP.Net/IIS it was actually quite hard to stop IIS 6 (?) from swallowing your 500 xml response and serving a custom html error page. If I remember correctly some browsers didn't support PUT properly either.
So while you are technically correct, the codes were in use, you are historically wrong, few people outside of a small community understood their use.
I remember this article from the first time around, when people were really getting into REST and there was a fierce debate about strict REST Vs RESTful. In reality RESTful has mainly won and this article was on the wrong side of history.
> So while you are technically correct, the codes were in use, you are historically wrong, few people outside of a small community understood their use.
I started in the late 90s, and even back then they were commonly used. They weren't just well understood by developers, but they were actually in non-developer's lexicons as well. If you asked the typical geek back then what a 404 was, chances are they'd be able to tell you that it meant something was missing. So I don't agree with you that they were understood by "few people outside of a small community" at all. Using status codes has been standard practice for decades. Maybe it took a couple of years at the beginning of your career for you to notice them, but there simply wasn't this time period of decades when they weren't in use until REST came along.
404s are a different matter because you'd get 404 pages, so it's not at all an argument to support your position. It doesn't mean developers understood what to return from an ajax call, or that they understood HTTP verbs.
I'll remind you again that it was actually fairly hard to return the correct codes from a lot of frameworks, so objective facts are at odds with your recollection of events.
I stick by my assertion that the vast majority of web developers in our industry didn't really understand http until the latter half of the 2000s. I also specifically remember presentations to all our developers both junior and senior of how browser caching worked, which to most developers at the time was a bit of a mystery, and the correct headers to return to control it.
Here are some examples from 2008 of developers on SO discussing things which seem obvious today:
http://stackoverflow.com/questions/165779/are-the-put-delete... http://stackoverflow.com/questions/165720/how-to-debug-restf...
Ajax is not the only way to access a web service.
> 404s are a different matter because you'd get 404 pages
…which are returned with a status code of 404. That's where the name comes from. Non-200 status codes were ubiquitous even back then.
> It doesn't mean developers understood what to return from an ajax call, or that they understood HTTP verbs.
Ajax is irrelevant and we're talking about status codes, not verbs.
> I'll remind you again that it was actually fairly hard to return the correct codes from a lot of frameworks, so objective facts are at odds with your recollection of events.
Perhaps the technology _you_ were using made it difficult, but it certainly wasn't the general case. PHP, classic ASP, mod\_perl, mod\_python, CGI scripts… they could all respond with non-200 status codes easily. Which ones are you thinking of that made it difficult?
> Here are some examples from 2008 of developers on SO discussing things which seem obvious today:
Come on man, clueless questions get asked about extremely well established things on Stack Overflow every single day. That doesn't mean that those concepts are suddenly no longer well understood, it just means that the person asking is a beginner. And neither of those questions mentioned status codes at all!
There's badly written buggy software from any time period doing all sorts of crazy shit, but only accepting 200 certainly wasn't the norm, or even commonplace back then.
You may be thinking about DNS hijacking by ISPS, but not non-200 issues. There are bound to be some terrible apps out there that respond badly as well, but that's really no excuse.
For example:
Response 403
{'error': {'errors': [{'domain': 'global', 'reason': 'forbidden', 'message': "Required 'compute.instances.list' permission for 'projects/golden-sandbox-162219'"}], 'code': 403, 'message': "Required 'compute.instances.list' permission for 'projects/golden-sandbox-162219'"}}
See the Remarks section: https://msdn.microsoft.com/en-us/library/system.net.httpstat...
Other client plugins may have similar issues.
If your API will never be navigated by a human operating a browser, a lot of the REST specification is inapplicable (navigation links, etc.)
So you're throwing out a lot of REST regardless, and the question becomes where to draw the line between ease of implementation and compliance with a standard that doesn't really fit your needs.
It turns out that the semantics of RPC — attractive as they undeniably are — are pretty poor for building real-world distributed systems, while those of REST as a pretty good (or at least better) fit.
Personally I like to very selectively add RPC actions on top of the base resource. Tacking an RPC action onto the resource URI allows you to encapsulate the intent of the user's action, handle all the updates required server side, and then return the updated representation.
So it's usually POST resource/:id/action and that's fine.
There's nothing wrong with that. It's not anti-REST or anything, assuming you satisfy the other REST constraints, ie. each request is self-contained and any stateful resources are designated by URLs.
As an aside, I'm personally not a huge fan of human-readable URLs because it encourages API consumers to rely on/construct URLs client-side, which is not REST.
Certainly a PUT solution might have some advantages for replayability in case of network partitions, but REST doesn't this choice dictate one way or the other.
But that's what an application is - a human navigating an api
That's incorrect. REST was designed for services of all kinds, not just human interfacing services.
The point of links is to support service upgrade via good old encapsulation. Consumers of your API shouldn't just guess links like is commonly trumpeted as REST, they should navigate to the part of your service they need from a well-defined endpoint, and this navigation path has a well-defined lifetime specified by cache control headers (HATEOAS).
The service promises to honour the lifetime of any visited URL on that path as specified by said headers, and any client trying to use that path after the expiry date must be prepared to possibly receive error codes.
I agree on all points of this article. The only nitpick I have is that tunneling through GET/POST is strictly necessary for HTML forms, since they do not support other verbs.
Only if you ignore AJAX in its entirety. Yes, the browser's capabilities are limited, as it must be a common denominator and can't describe every situation, and thus, can only GET/POST in certain forms.
What if I can ask my OS to do things I normally do over some protocol like HTTP in a RESTful style? Create user, list directory, find the last login, tell me linux kernel version.
^ has been done as a separate monitoring tool like Osquery, but can't we make such protocol natively? I don't want to parse my command-line output if I can just speak in one human-readble, machine-friendly dialect.
The /proc filesystem is somewhat close to that when it comes to GET.
>I don't want to parse my command-line output if I can just speak in one human-readble, machine-friendly dialect
That's not what REST (the original concept) is about.
HTTP/1.1 is a specific architecture that, to the extent I succeeded in applying REST-based design, allows people to deploy RESTful network-based applications in a mostly efficient way, within the constraints imposed by legacy implementations. The design principles certainly predated HTTP, most of them were already applied to the HTTP/1.0 family, and I chose which constraints to apply during the pre-proposal process of HTTP/1.1, yet HTTP/1.1 was finished long before I had the available time to write down the entire model in a form that other people could understand. All of my products are developed iteratively, so what you see as a chicken and egg problem is more like a dinosaur-to-chicken evolution than anything so cut and dried as the conceptual form pre-existing the form. HTTP as we know it today is just as dependent on the conceptual notion of REST as the definition of REST is dependent on what I wanted HTTP to be today."
[1] https://web.archive.org/web/20091111012314/http://tech.group...
"We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server.Session state is therefore kept entirely on the client." - from Fieldings dissertation.
To be fully compliant you have to do use something like HTTP Basic Auth, where you resend the username and password with each request.
I think you should use cookies to store a token that the server can then use to determine whether the "context" of the request is "logged in" or not. I do it. But it's technically a violation.
My point is that Cookie does provide the credentials required for the call contex, this fulfilling the self containment requirement.
They probably shouldn't be used like that, but technically it would be compliant with the requirements you've quoted.
Link?
A web site I used recently puts your session ID in the URL. If you log in, then alter the URL to remove the session ID, you appear logged out.
It gets even worse. Clicking the "Log out" button on the page simply removes the session ID from the URL. If you go back and reload the web page with the session ID in it again, you still appear logged in.
The page also doesn't use HSTS so is easily vulnerable to SSLStrip.
There's no other mechanism to associate an HTTP request with back-end state (logged-in/out, etc.) except for session identifiers transmitted by the client browser (through cookies, headers, request parameters).
Nothing inherently wrong with that, but it depends on the situation.
> Clicking the "Log out" button on the page simply removes the session ID from the URL. If you go back and reload the web page with the session ID in it again, you still appear logged in.
That's bad.
Just because something becomes an often-misapplied buzzword doesn't say anything negative about the original concept so much as the people mis-implementing it.
What ever happened to plain old RPC? Have we stopped to consider that people tunnel things through POST or GET requests because it's easier and more flexible than trying to cram your functionality into GET, POST, PUT, PATCH, or DELETE?
If you find yourself using a lot of these anti-patterns, maybe you should consider switching to something a little less "REST-ful".
Even the HTTP monopoly is changing. There are lots of new protocols (HTTP2, QUIC, WebRTC) that work besides firewalls and things like ALPN gives a standardized way to tunnel new protocols over an encrypted connection.
The article might note it, and Roy might insist on it, but nobody cares.
For all intents and purposes, what people call REST in practical use is RPC over HTTP with JSON responses.
Well, HTTP itself is the archetypical REST API, though.
I ask because I'm going to start writing my first http api for a small SPA.
RPC and client-server contracts, as well as static-typing, is a bloody god send and the whole world will be in a better place once we formalize and accept it (I didn't say standardize I said formalize).
More complex use cases, and specifically non-idempotent operations, is where I find REST doesn't hold up as well as RPC.
REST isn't about human-readable URLs. The link to the comments should have been part of the representation returned for /video/1093 (typically JSON these days, so a "comments" property of the object).
REST is just a set of rules to follow that attempt to avoid some pitfalls and provide a common parlance.
/account/1 is REST because the you're looking for an account (noun), the account id is 1, and you're using the HTTP method GET.
/search/hello is RPC because it uses a specific verb (search) to call a remote procedure to search for the 'hello' keyword. You're taking an action for which there is no appropriate HTTP method, so RPC can be used instead of REST.
This doesn't cover 100% of every situation, but it's useful as a quick mnemonic.
Probably not. If "what this is and how it relates to other things" is determined by looking at the URL path and not the media type (for "what it is") and link relationshops (for how it relates to other things) it's not REST.
But the unicorn "properly designed REST api" is quite nice.
Since i can't trust anyone to do it right though, I'll just use GraphQL because its easier to get people to do right.
REST is about architecture, about where state should live, how long it should live, how messages between entities should designate resources/state, all so you can preserve encapsulation and maximal flexibility for service upgrade. Your service is not RESTful if you don't meet these criteria.
RPC has no such restrictions, which means you're free to do everything wrong, which virtually everyone does, and you'll still be doing RPC correctly.
the main difference is endpoint negotiation vs object state transfer - consider an account representation - if you can withdraw, the link to perform the withdraw operation is there in the server response. if you can't, the link to the withdraw operation is not there. this is how the returned value convey the object state and how it let client explore object operarions.
say, it's the difference between returning an object instead of a struct, and it's also why json alone is not compatible with rest, there's not an agreed schema to identify operations coming along with the data so that a client can actionit - json-ld and hal can, if you reallyhate the idea of xml tho.
That said, REST is not the right fit for _every_ use case. The same simplicity mentioned as a strength also limits its flexibility. I think this is no more abundantly clear than microservice oriented architectures. More and more these architectures are moving towards different patterns/protocols for various reasons (gRPC comes to mind).
REST is not fundamentally inappropriate, it just needs a lot of careful design about domain objects, link relations, and media types. Generally, people are not very good at thoughtful design.
It didn't help that REST began to trend as an idea right around the same time that intentionally schemaless JSON was replacing schema'd XML documents as the preferred way of over-web information interchange. For consumers, schemaless JSON snippets were attractive for partial processing; for developers, they were attractive for rapid iteration. For makers of "Web 2.0 Mashups", JSON-returning APIs were attractive because processing XML with circa-2006 "cross-browser" nightmare-mode Javascript was about as pleasurable as pulling teeth.
People saw these APIs being called REST, they tried to understand REST, got overwhelmed halfway through, called it REST-like or RESTful instead, and that's how we arrived at where we are.
During this time, RPC wasn't cool or buzzword-compliant, so the people who still RPC did it for good reasons and didn't really blog about it. The quip to consider RPC is nonetheless valid; stuff like gRPC or Thrift are at least proper RPC frameworks, and a much better idea than someone trying to ducktape something with GET and POST for the millionth time.
Luckily, soon, GraphQL will be the newest entrant in this space, and will have to contend an influx of superficially-informed people enticed by its promise. It may have a better track record than REST, because a partial implementation of GraphQL will better resemble GraphQL than a partial implementation of REST will resemble REST.
Especially if it's not worth the effort.
Yes, waterfall was a mistake, but design-nothing is mistaken too. Thinking before doing helps avoid waste & rework.
The best we've got on this mark is the Waterken server, which is pretty good, but not good enough.
REST is more "hodge podge of concepts" that you can hack on and pollute and misunderstand at will.
I guess nothing will stop people from making Frankenstein schemas or poorly performing resolvers but at least the consumption is mostly uniform?
That's my impression too.
But this seems to be the case for a lot web stuff.
Most use POST for that now, but there is room, or should be room for RPC-style endpoints in a mostly REST service, and vice-versa.
REST doesn't have a handful of verbs, HTTP has a handful of predefined verbs (but supports extensions). REST is an architectural style that does not specify the underlying protocol.
> What if none of the status codes make sense?
Again, that's an HTTP issue not a REST issue. And it's not likely to be a real issue (HTTP status codes may be insufficiently precise—but already support additional data for disambiguation—but I can't imagine a situation where none of them make sense.)
Or perhaps people actually don't understand REST, but think they do, thus leading to endless blog articles about "REST levels" and other nonsense.
> What if you can't shoehorn your functionality into the handful of REST verbs?
GET and POST can represent any arbitrary program (they map to the lambda calculus after all). You don't need any more than that, in principle. The other verbs are merely optimizations.
> What ever happened to plain old RPC?
The inescapable failure modes of RPC are exactly what REST addresses.
IDK. Whatever happened to plain old REST HTTP?