What Is a REST API, and Why Yours Probably Isn’t One
Posted by fagnerbrack@reddit | programming | View on Reddit | 24 comments
Posted by fagnerbrack@reddit | programming | View on Reddit | 24 comments
lelanthran@reddit
Putting auth/id/session tokens in the message is a really bad idea! Don't do it.
Leave it in the header, where intermediaries can handle auth/id/session. If an intermediary needs to replace the session token, it can do it in the header. If the token is in the body the intermediary has to parse the entire body first before sending the request on downstream.
fagnerbrack@reddit (OP)
Why is it a bad idea when a site used TLS?
lelanthran@reddit
Because then you can't proxy requests to an intermediary that provides the actual security token, the app generating the body needs to be given the security token.
Think about using an agent that makes web calls: you don't trust the agent to have your credentials or any bearer token, so you give it a token of
__SESSION_TOKEN__, and proxy all requests through a proxy that replaces the__SESSION_TOKEN__in the header with the actual token.Difficult, if not outright impossible, if the server forces the client to put the token in the body and not the header.
fagnerbrack@reddit (OP)
You're talking about encoding load balancer decision making into http and not application-level messaging. If the proxy understands the protocol (header, body, cookie) then it doesn't matter.
There's tradeoffs to everything and using an example that fits other tradeoffs doesn't invalidate the idea where it makes sense (application-level auth in say a server less lambda environment). Not everyone needs to care about load balancing, there are other approaches to solve the problem and they may or may not benefit of hateoas
cym13@reddit
It's always interesting to look at the origin of common ideas and how they differ. This is no exception. I'm not familiar with HATEOAS but it looks like an interesting design.
That said, I also believe that things often evolve for a reason. Having a security-oriented mindset, the discussion of the stateless property jumps out to me somewhat. It's not that I dislike statelessness, on the contrary I like it very much in most cases as it makes it easier to reason about the application and verify its constraints. But while using something like /user/me instead of /user/429 isn't stateless, it does something very useful from a security perspective: since you never send a user ID you don't need to check that the user id corresponds to your user (a necessary check to ensure you're not able to access other users' data). This principle can be generalized as the minimization of attack surface: the less information you send, the less an attacker has to work with and the less code you have to check for bugs. Under that principle, you would ideally send as few data as possible, and if some information is already known on the server side you should take it from the server and not the user.
But of course if you have to rely as much as possible on what the server already knows, it's difficult to also be stateless, so there is a fundamental conflict between the two. And the less stateful your application is, the less cacheable it becomes so that's two REST principles at odds with one of the most fundamental security design principle. And the world now isn't the same it was in 2000, security is rightfully at the core of many people's considerations (be it only for regulatory reasons).
I'm thinking of HATEOAS in that context as well: should the API present only the actions that the user has access to (which isn't stateless) or show every possible action and check the user's privileges when they attempt that action (which communicates, for example, admin-only features that a regular user wouldn't normally know about).
And of course security isn't the only thing that changed in almost 30 years. I don't have a magical solution, but I don't think simply saying "Your REST isn't pure enough" works. I would find interesting however to have a REST 2.0, a new take on REST that attempts what Fielding tried in his time but with an understanding of modern constraints.
tsimionescu@reddit
HATEOAS would 100% advocate for the first design, not the second.
The whole point of REST is that application state should be driven by the server state, and the client should simply know how to interpret the data types that the server sends, without any other logic. So, for example, HATEOAS/REST has nothing against a URL like /user/me being the URL for the currently logged in user, based on cookies or other forms of session state. The problem REST has is if this URL is hardcoded in the client, instead of having the server tell the client "here is the URL for your user: /user/me" as the response to the login request.
xiaopewpew@reddit
It is perfectly ok to write apis to send json over http and call them rest.
wildjokers@reddit
It is ok to call an apple an orange.
TheBoringDev@reddit
This is more calling a tomato a vegetable. It’s biologically a fruit, but if you argue that in a culinary context people will just get annoyed.
xiaopewpew@reddit
I have definitely worked with a few pedantic people in my career sucking the lives out of everyone around them arguing around trivial stuff like this.
Saint_Nitouche@reddit
I am morbidly curious, has anyone ever done HATEOAS for real? And had it reach production?
esanchma@reddit
Yes: https://spring.io/guides/gs/accessing-data-rest
wildjokers@reddit
Yes, we use HATEOAS. It is how the UI knows which operations are now available based on current state.
fagnerbrack@reddit (OP)
I really want to avoid self promoting here, but I have no other public code to show: https://github.com/Readplace/readplace.com/tree/main/projects/browser-extension-core
The browser extensions facade for Readplace uses hateoas with siren. Also the e2e tests explicitly crawl pages using playwright in an action based pattern.
Yes there's things to improve but it's a pretty good example where we can talk about the tradeoffs (clients are not perfect)
AWildMonomAppears@reddit
I tried it back in ~2012 when it was all the rage. It was a public API and we used Json URLs in fields to show the next layer. It was like call users get lost, every user would have a URL. We didn't go as far as showing what HTTP verbs were applicable so it doesn't really count. We didn't get much traction on the product and dropped it so don't know if it came to use.
oweiler@reddit
You know who uses HATEOS? Every webpage on the planet.
Nooooope@reddit
I thought HATEOAS was a good idea the first time I heard of it, but I don't really see the point now. It guess it helps with endpoint discovery if you're just learning how an API works by trial and error. But it's both harder to implement and much less useful than just creating real API documentation with something like Swagger. Am I missing something?
wildjokers@reddit
The value of HATEOAS is not endpoint discovery but rather available action discovery.
Swagger/OpenAPI documents what endpoints exist, but it doesn’t tell a specific UI, for a specific resource in a specific state, what operations are currently valid. That logic has to live somewhere. With HATEOAS, the server can expose the valid transitions/actions directly in the response, so the UI doesn’t have to duplicate business rules like “can this payment be cancelled?” or “can this account be edited?” or “is this transfer still reversible?”
When the set of available operations depends on state, permissions, workflow, product rules, etc., HATEOAS can be really useful. It keeps the authority on the server and lets the UI react to what the API says is actually available, instead of reimplementing that decision logic in multiple clients.
Nooooope@reddit
Thanks, that's a better use case than I was imagining.
The__Toast@reddit
Good engineers optimize for the most simplistic implementation that meets the requirements, often without even thinking about it. These frameworks may be great for complicated web interfaces, but are entirely unnecessary for the crud apps that make up the bulk of business software.
MidgetAbilities@reddit
The versioning paragraph is very hand-wavy to me. HATEOAS only “saves” you from very superficial API changes.
zjm555@reddit
A REST purity article? What is this, 2015?
amakai@reddit
Not sure I understand the point of HATEOAS.
It sounds cool on paper, but if my client knows that in the response body there's a leaf with "items", then my client can also just know that "/resource/items" is the URL. One way or another I need to hardcode either existence of a leaf or a specific URL.
And if the API evolves, and the "resource" now has "kettles" leaf, I still have to modify my client to support that in any meaningful way. How is that different from just adding new hard-coded URL?
The only marginal benefit I can think of, is changing the URL, like from "/kettle" to "/kettles". But even then, if you are expecting every client to not use the raw URL and instead use this additional routing layer in message body - why even bother with changing URLs? They can be UUIDs at this point as you just moved routing to another layer altogether.
Gwaptiva@reddit
Why nobody cares about purity, but rather has something that works