6 ms·
HATEOAS has never really grabbed me. Not least because, despite HN now swung hard against microservices, they exist often for a reason, and it's difficult for
by beachy 5y ago
HATEOAS has never really grabbed me.
Not least because, despite HN now swung hard against microservices, they exist often for a reason, and it's difficult for one service to emit hypermedia for another.
The inspiration was humans surfing freely through interlinked web pages, but API clients just don't naturally do that.
- bryanrasmussen 5y agoI always understood application in HATEOAS to be referring to the browser or whatever type of application sitting on some machine somewhere had been written to consume hypertext, but it sounds like you're considering a service to be the application?
- beachy 5y agoI was referring to something like this. Here's a hypermedia API entry point I googled up. GET / { "version": "1.2.3", "description": "Example API to manage orders", "links": [ { "rel": "orders", "href": "/orders" }, { "rel": "customers", "href": "/customers"}, { "rel": "customer-by-id", "href": "/customer/{id}"}, { "rel": "customer-by-email", "href": "/customer{?email}"}, ... ] } My point was, how is such an API served up when it spans resources that are managed by two separate services / microservices - one for customers, one for orders? Of course this is a simple example, we are smart tech heads, so obviously we can wedge a third service in front of the other two, which exists solely to provide aggregating behavior like this. But why? Is hypermedia so useful that it's worth going to this trouble? (No IMHO).
- eyelidlessness 5y agoDjango REST Framework (and I’m assuming later work by its authors) get this right and literally populate URLs rather than giving you patterns.
- beachy 5y agoNot familiar with Django sadly but it sounds like it would act as something of a proxy that sits in front of your microservices. My point is that if you are starting with just e.g 2 microservices, one for customers, one for orders, then hypermedia on it's own is not useful enough to justify adding a new proxy/ layer, just so that an API produced by one of those microservices can include hypermedia for the other.
- eyelidlessness 5y agoIt’s just providing a Uniform Resource Identifier. Doesn’t say anything about how you micro your services.
- nmadden 5y agoDon’t you just return links that refer to the other service? (ie absolute URLs). That is kind of the point of hyperlinks: the service hosting a resource can change, and you just change the links you serve rather than changing lots of hard-coded clients.
- beachy 5y ago(the example I used is so simple it didn't really highlight the difficulty) My point is that one microservice cannot easily generate links for another. How does the customer microservice (that wants to be hypermediaful), generate a deep link into the order microservice, e.g perhaps to obtain the latest order for a customer? It can't, unless it is uncomfortably tightly coupled to the other microservice. The most pragmatic solution is not even to try. Better to pass on the hand wavey HATEOAS stuff, and just tell the developers to work from the API documentation.
- nmadden 5y agoWhy do you think it’s hard for one microservice to generate links to another microservice? The alternative is that all the clients are tightly coupled to both of them.
- beachy 5y agoThe alternative may not be palatable to you but IMO if two microservices have an encyclopedic knowledge of each other's url structures, then they aren't really separate microservices at all.
- nmadden 5y agoWell indeed, but the hyperlinks here are just surfacing the coupling that already exists between those services. Making explicit an already implicit coupling. Two other points: - you can use HATEOAS to let one microservice discover the links it needs from another, exactly as a client would do. - by not using hyperlinks you have not solved the problem, you’ve just moved the requirement to know the URL structure from another microservice (that you control) to dozens or hundreds of clients, that you likely don’t control. This makes your services much more brittle, not less.
- incrudible 5y ago> Is hypermedia so useful that it's worth going to this trouble? No. It's a pointless indirection. These APIs are universally awful to use. I'd also rather you provide a library that abstracts your poor taste in HTTP API design. If I have to navigate your HATEOAS swamp, you better make up for it by being really important (PayPal).
- zorr 5y agoIt never really materialized because of a chicken/egg problem between API's and clients/tooling. And OpenAPI/Swagger also filled some of the space. Imagine if tools like Postman/Paw/browser-devtools supported HATEOAS.
- treve 5y agoI'm trying to (help) solve this: https://github.com/badgateway/ketting https://github.com/badgateway/ketting https://github.com/curveball/browser https://github.com/curveball/browser I've been working on this for nearly 5 years, and despite not being very popular yet, the technology seems pretty sticky for those that have adopted it. But there's gaps in the standards, and we need way more tooling for more ecosystems. But when it works, it works great.
- jseban 5y agoWhy would service-to-service communication use protocols and formats that are made for browsers?
- beachy 5y agoProbably not clear but I was talking about a situation where an API client (e.g a web application server) needs to manipulate customers (managed in one microservice) and also their orders (managed in another). Not the two microservices talking to each other. So the API client will be making separate API calls to each of the microservices. My premise is that it is too hard for API responses from the customer microservice (for example) to include hypermedia links to resources within the orders microservice.
- DeathArrow 5y ago>Probably not clear but I was talking about a situation where an API client (e.g a web application server) needs to manipulate customers (managed in one microservice) and also their orders (managed in another). I would use a microservice gateway with the client only talking to the gateway. It seems weird to me that the client can call any microservice.
- jseban 5y agoGot you. I just want to point out the absurdity of it. Java microservices commonly use Javascript Object Notation for their data transfer. How is that the right tool for the job. With all the translations that are needed, why don't they use RMI/RPC? And why even spend all that development time on something that you can solve in an afternoon with a JDBC connection anyway.
- rswail 5y agoBecause the paradigm of RPC is not about data transfer (which is the serialization protocol). RPC is one architectural style. It's pretty undefined other than "call/response". Marshalling of arguments is just a serialization issue. RMI/RPC doesn't work well across firewalls or org boundaries. It doesn't support separating internal and external host identification, so when you try to RMI to a host in another DNS domain that has a local name, there's all sorts of nonsense to get the Java runtime to understand it can have multiple DNS names and be associated with multiple network interfaces. JSON/protobuf/cap'nproto/ONC-XDR/XML are about serializing data (whether it's a resource or a marshalled argument/result for RPC).
- DeathArrow 5y ago>Not least because, despite HN now swung hard against microservices, they exist often for a reason, and it's difficult for one service to emit hypermedia for another. Why would microservices even need HTTP to talk with each other?
- ferdowsi 5y agoThere is an enormous amount of L7 tooling and practice that already exists for securing, optimizing, monitoring, and modifying HTTP traffic.
- naasking 5y ago> The inspiration was humans surfing freely through interlinked web pages, but API clients just don't naturally do that. There's nothing unnatural about it, it's just one extra step to use a name that the service must guarantee is stable rather than directly accessing a hard-coded URL which can be unstable. You're used to: var client = new HttpClient(); var result = client.Post("http://somehost.com/api/hardcoded-service-resource", /*pass some data*/); The resource URL is hard-coded with a specific structure and meaning, which means the service can never change it without breaking clients. A simple REST equivalent would be: var client = new HttpClient(); var entry = client.Get("http://somehost.com/api/entry").ParseHypermedia(); var result = client.Post(entry.StableNameForEndpointIWantToCall, /*pass some data*/); There's nothing all that unnatural about this. The key is that the entry point returns a description of the API using hypermedia which maps stable names to unstable URLs. This allows service to change its internal structure as long as the entry point returns a hypermedia result that has a stable structure. You can think of HATEOAS for APIs like DNS for API URLs. Calling it "unnatural" is like saying that hard-coding IP addresses in your clients is more natural than using DNS names. That's just crazy talk!
- Chris2048 5y agoBut DNS allows for redirection wrt IPs. How does HATEOAS do the same? First, you already have DNS, and can abstract wrt existing URL structure. second, you still need stable references to services in order to identify them, and they in turn need to have stable structure - Hence the only thing you can change is the top-level stuff? Why is that important?
- naasking 5y ago> But DNS allows for redirection wrt IPs. How does HATEOAS do the same? I gave a code sample above. The service's entry point exports a map of unstable URLs to stable names, just like DNS exports a map of unstable IPs to stable names. What I described is the most basic form of HATEOAS, but it also allows hierarchical structuring, ie. you can discover more URLs via any path through a hierarchy of hypermedia returned by URLs from the entry point. > First, you already have DNS, and can abstract wrt existing URL structure DNS abstracts IPs not URLs. You could come up with an encoding where you map URLs to subdomains, but now you're lifting application logic to influence infrastructure policy, where your devs are now messing with nameservers instead of just sticking to their HTTP application, and you're tied to DNS TTL instead of application-specific caching policies, and DNS insecurities (no TLS). For instance, with HATEOAS I can make a resource permanent, or live only a few seconds, and these are application-level policies I can define without leaving my coding environment. DNS just can't give you this control, so trying to shoehorn the flexibility that HATEOAS gives you into DNS is putting on a straightjacket.