Hacker News new | past | comments | ask | show | jobs | submit login

Why did the author of this blog post decided to pass web links in resources and completely ignored standard practices such as RFC 8288 which employs the Link HTTP header?

https://tools.ietf.org/html/rfc8288

Additionally, compact URIs (CURIES) are also widely used in this context.

https://www.w3.org/TR/2010/NOTE-curie-20101216/

I feel that the author tried to reinvent HATEOAS but skipped a cursory bibliographical review and jumped right into reinventing the wheel, and one which has already been reinvented multiple times (HAL, JSON-LD, etc...)




The post itself, and this response, illuminate a reality which we don't talk about -- the set of standards around HTTP are a horrible mess. As a person who in a past job has tried very hard to implement a "standards compliant" HATEOAS API, the sheer mass of complexity and vagueness is just too much. It's easier to just write something that works and which resembles something people are used to than to wade through these horrible RFCs trying to follow standards without good reason. It's like a horrible joke -- I wouldn't be surprised if you got to the final RFC and it said "Just kidding! Congratulations on getting this far, but this was just a test of your tolerance for pedantry."

This emperor has no clothes.


> the set of standards around HTTP are a horrible mess.

That's not the problem at all.

It would be the problem if the current state of the art was actually taken into account and discarded for some reason.

Instead, the state of the art (or even basic standard practices) is systematically ignored, and we end up seeing the same old wheel being supposedly invented again and again by people who fail to perform the flimsiest cursory bibliographical research on any given topic, and instead invest the bulk of their time announcing their poor reinvention of the wheel.

The web is based on linking. It's a very basic concept. Linking resources is not a new problem. What line of reasoning can possibly lead anyone to believe that this specific problem has never been researched by anyone before us, thus it's a sensible idea to simply dive head-first into coming up with a proposal that completely ignores any prior work?


Nope, the current state of affairs is an indictment of the "standards". It should be easy and obvious to implement something according to the standards, but it's not. I'm a relatively smart guy, and I've tried. You very quickly reach the point where you ask, "why the fuck am I doing this?" and just do what makes sense.

Let's take RFC8288 as an example since you've brought it up. Where in that RFC does it discuss _why the fuck_ I would want to put an API link in the headers instead of the body?

The fact is that this RFC isn't "the standard". The standard thing is to put API links in the body with other attributes, and it's the standard because that's what everyone does, and because that's what makes sense. This RFC is a hammer for HTTP pedants to hit people over the head with.

The web is based on linking

And where to we expect those links to appear? In the header?


FWIW, RFC 8288 was preceded [1] by RFC 5988, and RFC 5988 [2] says in its section '1. Introduction':

"A means of indicating the relationships between resources on the Web, as well as indicating the type of those relationships, has been available for some time in HTML [W3C.REC-html401-19991224], and more recently in Atom [RFC4287]. These mechanisms, although conceptually similar, are separately specified. However, links between resources need not be format specific; it can be useful to have typed links that are independent of their serialisation, especially when a resource has representations in multiple formats."

"To this end, this document defines a framework for typed links that isn't specific to a particular serialisation or application. It does so by redefining the link relation registry established by Atom to have a broader domain, and adding to it the relations that are defined by HTML."

[1] https://tools.ietf.org/html/rfc8288 [2] https://tools.ietf.org/html/rfc5988


it can be useful

Such as in which situations? It's not obvious at all, so a reader (that is, an API designer) is on their own to try and divine whether there's any real reason to follow this "standard" instead of doing things in the more natural and standard way.

This is my point. Not that it's hard to read these RFCs... but that they're often so vague, and is so often hard to know whether there's any benefit at all to following them in one's specific situation.

That doesn't stop self-appointed standards cops from smacking people down.


I might be missing the obvious, but I don't see in your quote the answer to the question:

> Where in that RFC does it discuss _why the fuck_ I would want to put an API link in the headers instead of the body?


The answer is in the part that says "it can be useful to have typed links that are independent of their serialisation, especially when a resource has representations in multiple formats".

In HTTP, URLs locate a 'resource'. Then you and the server do content negotiation, implicit and/or explicit, to select a 'resource representation'. Think of these as different formats for the same conceptual thing identified by the URL. Some formats like HTML can support hypermedia that can have embedded links. Some, like 'text/plain' or 'image/gif', can't.

Link headers allow links from the current resource to other resources to be communicated even if the chosen representation can't communicate links in its body.


Got it, thanks. How do you define 'the chosen representation can't communicate links in its body'?


You as the client try to GET /my-receipts/20190512-1 from Fancy Receipt Scanning Service, and content-negotiate with an Accept header to "text/plain" or "image/gif" (e.g. to get a plain copy or a scan). There's no agreed-upon way of communicating links in plain text or GIF, so Fancy Receipt Scanning Service can't serve you a GIF scan of your receipt that links to a product page for every item you bought.

If you accepted "text/html", it could have served HTML that embedded these links within the response body, but you didn't accept "text/html".

It can choose to send links as headers, if it still wishes to communicate links.


That's fair, but if I'm defining an API that serves, say, JSON, I can define a schema for it and tell my clients what things mean in the schema, including which things are links.


> Nope, the current state of affairs is an indictment of the "standards".

That's not true at all. Those "standards" are not taken into account at all. I mean, there are currently about half a dozen HATEOAS standards and specifications that repeatedly implement the same concept, and they have existed for quite a few years. Yet, how many of those standards and specifications were taken into account in this particular blog post? Zero. Instead of taking into account any prior work already done on the issue of web linking, the problem is for some reason presented as a novel idea that, for some reason, no one in the world would have ever thought about.

How is that a reasonable starting point?

> It should be easy and obvious to implement something according to the standards, but it's not.

You got to be kidding.

Let's consider RFC8288. RFC8288 in essence specifies a single HTTP header and a format to represent link relations. You want to link your resource to any other resources? Well, just add the link relations. You want to check what resources are related to the resource you've just requested? Well, just check the Links headers.

Let's consider Hypertext Application Language (HAL). HAL in essence specifies a wrapper document type that extends the resource with a "_links" name:object pair. You want to link your resource to any other resources? Well, just add the link relations to the "_links" object. You want to check what resources are related to the resource you've just requested? Well, just check the object referred by the "_links" name.

Let's consider the Ion Hypermedia Type. Ion in essence specifies a wrapper object type that includes all link relations as JSON name:value pairs and contains the resource as the value of the "value" name:value pair. You want to link your resource to any other resource? Well, just add the link relation as a name:value pair. You want to check what resources are related to the resource you've requested? Well, just check the name:value pairs of the response object.

And the same applies to other HATEOAS standards and specifications such as JSON-LD, Hydra, Collection+JSON, Siren, etc etc etc...

Where's the rocket science?

> Where in that RFC does it discuss _why the fuck_ I would want to put an API link in the headers instead of the body?

You can't be serious.


As someone who is wholly unfamiliar with this, why should relationships be treated any differently than any other attribute of some object returned by a web api?

If data-attributes have to be parsed out of some json-body, but link-attributes have to be parsed out of the header, that's weird. It becomes even weirder if I decide to switch from using a key-in-the-body to a link-in-the-header.

That doesn't sound easy or obvious. As is, as someone dealing with a REST API, I rarely, if ever, have to think of headers. When I do, they're related to things like CORS, and transport layer semantics, not application level semantics. But now you're saying that, actually, some of my application semantics should be in the header, but most should be in the body.

How is that easy or obvious? Why is that better?

I'm dead serious, I'm not kidding, I'm not the user you just responded to.


> As someone who is wholly unfamiliar with this, why should relationships be treated any differently than any other attribute of some object returned by a web api?

Because links are resource metadata, not the resource itself let alone entities represented by a resource. The relationships between resources are independent of the resources themselves.

> If data-attributes have to be parsed out of some json-body, but link-attributes have to be parsed out of the header, that's weird.

It really isn't. In fact, it's the other way around. Link relations depend on the request, not the resource, just like the particular version of the resource (see ETag header) or the date and time at which the origin server believes the resource was last modified (see Last-Modified header).

Considering the petstore example, it would be weird if the pet would include a version/hash or the last time it was modified. A pet is a pet. It has a name, a species, a breed, and an owner. The pet resource is the pet information that you received as a response to the request you've made in a specific moment in time.


> Link relations depend on the request, not the resource, just like the particular version of the resource (see ETag header) or the date and time at which the origin server believes the resource was last modified (see Last-Modified header).

Not really. Since it's mother's day, the fact that I'm related to my mother is an attribute of me, not an attribute of the request you make for information about me. I am related to my mom.

In a conventional database, link relations are defined on the tables themselves, but versioning information and last-modified information is normally defined in metadata tables. So I don't see any prior art for this. It just doesn't match how most people normally represent objects.

> and the pet resource is the pet information that you received as a response to the request you've made in a specific moment in time.

And at version X, the pet has a specific owner, defined as a relation on the pet itself. The request provides versioning information, but the owner is keyed on the pet, just like it would be in the server's database.


> Not really. Since it's mother's day, the fact that I'm related to my mother is an attribute of me, not an attribute of the request you make for information about me. I am related to my mom.

You are related to your mother, but that relationship is represented through link relations. You are represented by your resource, and your mother is represented through her resource. Where and how those resources are represented or found is an entirely different concern that has absolutely no relation with the relationship between you and your mother.

> In a conventional database, link relations are defined on the tables themselves

Actually, they are not. I mean, there are entity tables (the resources) and then there are the relationship tables (the... relations). Although some techniques involve using non-normalized databases, that does not mean that entities and entity metadata, such as relations, are or should be conflated.

Now, imagine that the database tables weren't fixed properties of the system, which is a basic design issue in resource-oriented architectures. Would it make any sense to hard-code references to other tables if they could change at any point in time, specially if you're operating a system that could cache table rows?

> And at version X, the pet has a specific owner, defined as a relation on the pet itself.

Yes, and that's also the wrong way to go about specifying the relationship between resources. The correct way would be to express the relationship between resources as a link relation. The identity of neither the pet or the owner depend on each other.


> Actually, they are not. I mean, there are entity tables (the resources) and then there are the relationship tables (the... relations)

Foreign keys are put in entity tables in normalized databases.

> The identity of neither the pet or the owner depend on each other

So then the only thing that belongs on the pet itself is an arbitrary id? Because the identity of the pet doesn't depend on it's age or when it was born, and a timestamp is just a timestamp, so putting "time of birth" could just be a link relationship to another entity.

Same for breed. Location too, that's not a tool for identifying the pet. Heck, even the name is often defined by the pet-owner relationship but not the pet itself.

So we're left with a pet object that has only a uuid, and a set of link relations in the headers.

Why is that better? You've said my way is "wrong", but you haven't actually explained what your way does to improve the situation. I just demonstrated that any arbitrary piece of info can be represented as a link relationship, so the whole thing is arbitrary anyway.

So the simple question, the only question is, as a designer or user of an API, how does sticking some relationships in headers make my life easier? How do I decide which relationships those should be?

You clearly have opinions on how this should be done, but neither you nor the RFC explains what I gain from your way of doing things. So again, I'm not asking what I should do, I'm asking why?


> As is, as someone dealing with a REST API, I rarely, if ever, have to think of headers.

Really?

Headers contain information about the content and the caller which are used in business logic. Authentication and authorization information is often passed in headers, for example.


The state of the art for web APIs, for better or for worse, is ones where you send and receive 'untyped' JSON (served as application/json), endpoint URLs have version numbers in them, and POST GET PUT DELETE mostly map to CRUD. Some extra flourish is sprinkled on top, not to improve functionality, but to chase the mood of the times or to make your code-generator (like Swagger/OpenAPI) work.

The article appears to start with a very similar assumption, and proposes use of URLs within resource representations instead of bare foreign-key IDs. I don't think the article can be accused of systematic ignorance of 'standard practices' or failing to perform "cursory bibliographical research"; stuff like HAL and JSON-LD are far from standard practice.

This series may benefit from a quick comparison of API design schools, comparing ways to express the a similar domain model in various styles, but it also seems to be trying not to get bogged down and dispense some prescriptive advice (instead of, say, overwhelm and despair).


> The state of the art for web APIs, for better or for worse, is ones where you send and receive 'untyped' JSON

JSON is just a document format used to encode resources. Links between resources don't change with the document format used to encode the resources. Conflating resource encoding with resources, let alone resource linking, misses the whole point of a resource-oriented architecture.

> endpoint URLs have version numbers in them

That's an API design choice, and one which has no relation with how resources are linked. It makes absolutely no difference where a resource can be found, as long as it's reachable. That's the whole point of REST.

> and POST GET PUT DELETE mostly map to CRUD.

That's entirely irrelevant to how resources are linked.

> Some extra flourish is sprinkled on top, not to improve functionality, but to chase the mood of the times or to make your code-generator (like Swagger/OpenAPI) work.

Again, entirely irrelevant. Resource and resource representation are entirely different concepts. In fact, some web api frameworks actually pick resource encodings depending solely on the content type negotiation process, while using the exact same resource regardless of any encoding.


>> the set of standards around HTTP are a horrible mess.

> That's not the problem at all.

sorry, what is the real problem then, in your opinion?

i have never heard of that link in headers RFC until now. i have never heard of CURIEs but i remember seeing the xhtml example they gave. no one called them curies.

there is a huge communication gap, it seems, between what the standard defines and what people do in practice.


Why did the author of this blog post decided to pass web links in resources and completely ignored standard practices such as RFC 8288 which employs the Link HTTP header? https://tools.ietf.org/html/rfc8288

Who uses this "standard practice"? I haven't seen it. It seems rather awkward, even user-hostile, to put most of a resource's attributes in the body but put ones which happen to be links in the header.


Resource links aren't a part of the resource. They are only a means to express how the resource you've just requested is related to other resources. Thus it's a function of the HTTP request and not the resource itself.

I mean, think about it. The resource can (and will be) cached. Does it make any sense to also cache ephemeral links with it?


> Resource links aren't a part of the resource.

Then why are the single most important and widespread form of resource links, HTML URLs, always included in the response body i.e. in the HTML document itself?


HTML is a markup language whose primary goal is to provide human users with a readable and navigatable document through a web browser.

There's a reason why HTML is primarily used to provide human-readable documents, while web APIs are implemented based on other document formats that are better suited to provide machine-readable resource encodings.


Let me explain why you have reached the wrong conclusion. The key is to think about why the markup is needed. Is it to format documents, to make them 'readable'? No, it's to tag documents with semantic meaning that computers can use to enable richer content and behaviours. That's why, for example, tags like `<b>` and `<i>` are nowadays widely accepted to be design mistakes in HTML, and we use CSS instead for formatting. That's why we encourage semantic markup like `<section>`, `<nav>`, and even `<div>`.

Hyperlinks are one of the basic semantic markup tags. They allow machines to read them and insert jump points. The key here is that they are machine readable to enable behaviour that wouldn't be possible otherwise.


Right.. so... that doesn't jibe with how the real world thinks about these things. In the real world we want the pet to have an "owner" attribute, which is part of the resource.


The real world is outside Google and (at least try to) follows the RFC standard.


The pet does have an owner. It's another resource, however, whose location can and does change.


You should just know that this makes zero sense to most of us. Either that's because it makes no sense, or you can't explain it well, or we're all too stupid to get it. Either way, good luck with that "standard".


> You should just know that this makes zero sense to most of us.

Unless you've held an election, you only speak on behalf of yourself and yourself alone. If you're having a hard time understanding basic concepts then naturally it's unlikely that you'll have an epiphany in a discussion where you're decided to take an hostile stance towards details you're not understanding.

Meanwhile, you can ponder how these specifications you're claiming you and those you claim to be representing don't understand are actually used extensively, and it's such a basic concept that it even features in intro tutorials to REST APIs. Perhaps that's a good sign that basic concepts such as web linking aren't that complex or hard to understand as you've tried to assert they are.

https://restfulapi.net/hateoas/


They provide what you've described as an alternative to what most consider the normal way of representing resource links. It doesn't make any of the claims you are making as to why one is more valid than others.

So once more: sure we can do things your way, but why is it better? Every other source says link headers are an option. You claim they're superior. Why are they better?

Why does representing links in headers and not bodies make the API easier to understand, navigate, or use? How does it clarify the interactions? What do I gain from it?

So far, all you've said is "relationships are metadata" or something, which is not how most people consider relationships, and even if it we're true, it doesn't explain why my response can't contain metadata, as long as it's marked as such.


I've built actual HATEOAS services for a few years now, and I work/chat with several people that do the same, including a few authors on this subject, and I don't think that the idea that "a relationship generally should not be part of the representation itself, because it's meta-data" is a very universal idea. I'd say far from it.

Aside from that, I'm curious how do you manage alowing API clients to create new relationships or change them?


> Aside from that, I'm curious how do you manage alowing API clients to create new relationships or change them?

What's hard to understand? If you add a resource then you update your link relations. If you actually tried to implement a REST API instead of RPC-over-HTTP then the client navigates link relations just as before. That's pretty much the whole basic premise of REST.


The thing I'm mostly curious about is situations where a client manages relationships. For example, you already have an 'article' resource and now want to add a new 'category' link to that article. Clients often need to be able to create new relationships, or perhaps remove them. I'm curious if you ran into this and if so, how you do this with just Link headers.


> completely ignored standard practices

Google NIH syndrome


It's ok if the author tried to come up with solutions for the problems he feels he has, but it is a complete waste of time -- his own an of those who spend any time reading this sort of blog posts -- if the post fails to take into account standard practices that are being employed for years.

As another example of how the author failed to take into account basic standard practices, the author asserts that there is no standard for HTTP headers that specify API versions, but this baseless assertion requires ignoring the fact that media type versioning does exist and has been used for ages. The author even realizes that a solution based on the Accept header, which he prefers to invent a Accept-Version header, would fit his requirements. Ok, so why doesn't he just follow what has been standard for quite a few years and simply state the document version in the media type, which already is supported by any content-based routing scheme and is cached quite nicely?


Your suggestion for using content_type for versioning makes sense if you believe it makes sense to invent a new media type for every entity in your domain model (customer, invoice, ...). I don't think this is a good practice. I always stick to the standard media types (application/json, text/html, ...)


The existence of an RFC is not the same as the presence of a standard.


> The existence of an RFC is not the same as the presence of a standard.

I explicitly stated "standard practices", not "presence of a standard".




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: