3 Comments

I guess HATEOAS is an attempt to partially address this, but still relies on knowing (at a minimum) the root resource path, and (likely) the 'key' (rel in this example) needed to navigate to other resources.

{

"id": "10",

"link": {

"rel": "designation",

"href": "/demoApp/employees/6/designations"

}

}

Presumably strongly typed clients (generated as part of the CI/CD process for the API) offer some mitigation, but I wonder if that's just hiding the coupling. Then there's the practical issue of requiring the developer (or some automated process) keep up to date with new versions of the auto-generated API client.

Expand full comment
May 20, 2022Liked by Kevin Rutherford

@Jon is right in that (REST through) HATEOAS solves this issue. Yes, you do need to know the root. Once you know the root you can negotiate the format that the response will have - so you get to Hydra, HAL, Siren, etc. The client and the server will always need to have a common understanding about the structure of the messages exchanged. The essential information is then discoverable by navigating the structure.

The same client can talk to multiple services without the need to know exactly what the meaning of the information is. The meaning is described and derived from the structure.

All these formats include ways to _evolve_ your API. This means that old clients will be parsing the old structure, and new clients will be able to do more with new fields from the structs. There is no direct coupling between them and there is no need to keep them in sync. The server and the client can evolve on their own.

(There a huge discussion around versioning, whether it is needed at all, whether they are part of URLs, media types, etc, but I'm going to skip that. In theory, a well designed API can just evolve.)

Having said this, there is a tradeoff to the experience the client can present to its users. Due to the generality of the meaning it can understand, it is not possible to present information in the most optimal way. This becomes more apparent when building complex and highly interactive apps..

We could go on forever about what exists on this space (and it is truly amazing), but I think this blog is focused more on coupling within a local unit of code (at least that's how I perceive it and I may be wrong). The same technics that are used to fix the coupling between a client and a server across the network can be applied to fix the coupling between a function and its caller. Clojure has created a culture around this. Rich Hickey's talk on spec (Spec-ulation) is about this. From his - very interesting - observations, tooling has been build to make such issues discoverable and preventable.

Expand full comment