TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Use links not keys to represent relationships in APIs

342 pointsby saregoabout 6 years ago

39 comments

twblalockabout 6 years ago
Here is the problem with links in a nutshell:<p>&gt; The server is now free to change the format of new URLs at any time without affecting clients (of course, the server must continue to honor all previously-issued URLs).<p>If you have to honor all previously-issued URLs then you aren&#x27;t <i>changing</i> your format -- you are supporting two formats from now on, the old one and the new one.<p>You can of course tell your users that you will deprecate the old format, but unless you are as powerful as Google your users may prevent you from enforcing a deadline for deprecation.<p>If the URLs in your API responses are FQDNs rather than relative paths, all of this gets significantly harder to deal with.<p>Even if you figured all of that out, links are not idiomatic if your users consume your api via an RPC or GraphQL.
评论 #19893049 未加载
评论 #19891015 未加载
评论 #19890797 未加载
评论 #19890963 未加载
评论 #19890998 未加载
评论 #19891490 未加载
评论 #19890973 未加载
评论 #19893367 未加载
评论 #19891373 未加载
评论 #19892447 未加载
评论 #19900563 未加载
评论 #19892981 未加载
评论 #19890689 未加载
评论 #19929807 未加载
评论 #19892423 未加载
raquoabout 6 years ago
I never had any uncertainty regarding where I can use a given entity id in a well designed API. Fix the naming and organization of your API if that&#x27;s a problem for your users.<p>Conversely, I often need to log or store API-provided entity ids on my side, and having to parse it out of a URL or store irrelevant URL bytes in my own database would be really annoying.<p>You&#x27;re not going to avoid the need to compile entity URLs on the client side either, unless you only make requests to entities returned by the API, which would be a weird constraint to design client code around.<p>I really don&#x27;t see the point to any of this.
评论 #19890216 未加载
评论 #19900147 未加载
评论 #19890611 未加载
WanderingWavesabout 6 years ago
I think this takes an overly-simplitisic view of APIs. Going by the primary example in the article, by representing a pet&#x27;s owner as a link instead of an id, they&#x27;re basically discounting the idea that there may be separate endpoints that take in an owner id. For example, if there was an endpoint that let you get the invoices by customer, you would still need to understand the templates for that endpoint.<p>More fundamentally, I think it&#x27;s trying to solve a smaller problem in the face of a much bigger one, you still need to know what the response of any given endpoint is going to be. Just because they&#x27;ve passed me a link, doesn&#x27;t me I don&#x27;t need documentation on what endpoint that link points to. I still need to know that the owner is a link to the people endpoint so I can properly parse that result. That in turn requires just as much documentation (IMO) to describe the relationships as it would to properly document your URI templates.<p>Obviously, the primary reason to use links over ids is to give the developers of the API more control over changing things like routes and Ids and whatnot, but I feel like it is a bit disingenuous to make it out to be a much better user experience or something, since it really isn&#x27;t.
评论 #19890820 未加载
评论 #19890891 未加载
评论 #19903346 未加载
评论 #19890422 未加载
k_bxabout 6 years ago
There&#x27;s literally not a single upside of this shown in the article.<p>&gt; The server is now free to change the format of new URLs at any time without affecting clients (of course, the server must continue to honour all previously-issued URLs).<p>No more than it was previously.<p>&gt; The URL passed out to the client by the server will have to include the primary key of the entity in a database plus some routing information, but because the client just echoes the URL back to the server and the client is never required to parse the URL, clients do not have to know the format of the URL.<p>Instead, you now have to require new kind of knowledge, one of the keys which must be present in schema and their meaning. E.g. knowing that &quot;pets&quot; key is present and leads to a relationship of a particular kind, with all the implicit logic added and documented. And what if you want to get pet&#x27;s owners with some additional parameter, like only getting ones which are exclusively yours? Would you need to edit that &quot;pets&quot; url adding &quot;&amp;exclusively_owned=true&quot;?
评论 #19903138 未加载
sbr464about 6 years ago
I don’t mind using a link, but I’d prefer to have both the exact id and the link to avoid having to parse a link in an unreliable way to get the actual id.<p>It’s interesting how GraphQL changes the base point of the article concerning documentation&#x2F;ease of api use.<p>In our GraphQL resolvers we typically add two fields, thing_id which resolves to the id string, and thing which resolves an object that you can drill into as desired.<p>I was starting to see a lot of GraphQL APIs only add “thing”, which meant you had to do a lot of queries like below just to get the id.<p><pre><code> thing { id }</code></pre>
评论 #19890469 未加载
评论 #19890319 未加载
评论 #19903421 未加载
geezerjayabout 6 years ago
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?<p><a href="https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc8288" rel="nofollow">https:&#x2F;&#x2F;tools.ietf.org&#x2F;html&#x2F;rfc8288</a><p>Additionally, compact URIs (CURIES) are also widely used in this context.<p><a href="https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;2010&#x2F;NOTE-curie-20101216&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;2010&#x2F;NOTE-curie-20101216&#x2F;</a><p>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...)
评论 #19890394 未加载
评论 #19890344 未加载
评论 #19890240 未加载
评论 #19892441 未加载
westurnerabout 6 years ago
A thing may be identified by a URI (&#x2F;person&#x2F;123) for which there are zero or more URL routes (&#x2F;person&#x2F;123, &#x2F;v1&#x2F;person&#x2F;123). Each additional route complicates caching; redirects are cheap for the server but slower for clients.<p>JSONLD does define a standard way to indicate that a value is a link: @id (which can be specified in a&#x2F;an @context) <a href="https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;json-ld11&#x2F;" rel="nofollow">https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;json-ld11&#x2F;</a><p>One additional downside to storing URIs instead of bare references is that it&#x27;s more complicated to validate a URI template than a simple regex like \d+ or [abcdef\=\d+]+
评论 #19890710 未加载
Illniyarabout 6 years ago
The idea of using uris instead of keys is not a new one (as has been mentioned by other commenters). Every few years the idea gets a resurgence of people who say that REST apis should be HATEOS and that <i>we are doing it wrong</i>.<p>It seems obvious that the cost-value for this is simply not there, if it was good enough, you&#x27;d see developers requesting it and many more vendors implementing it. So far I haven&#x27;t seen any recent changes that might skew the cost-value towards the uri&#x27;s favor, only the opposite (cue GraphQl).<p>Using uris have little benefits, but it does have the following problems:<p>As a user of the api:<p>* You need to keep an arbitrary length key in your database if you save references. It can cause some issues with certain setups (less so these days though).<p>* If you keep the entire URI as identity, then you can&#x27;t use multiple endpoints. For instance lots of companies have an endpoint for production and one for reports - using URI for one endpoint in another is quite awkward.<p>* Working with queries is troublesome, especially with get request. Consider searching for all transaction of a specific account, where the account&#x27;s identifier is `<a href="https:&#x2F;&#x2F;api.google.com&#x2F;v1&#x2F;account&#x2F;123`" rel="nofollow">https:&#x2F;&#x2F;api.google.com&#x2F;v1&#x2F;account&#x2F;123`</a><p>* Upgrading to a new version of the api (one with a different url like v1&#x2F;v2) now not only requires you to change your code to work with the new version, but also migrate all previous ids you kept in your database, which is a much different and more error-prone issue then simply changing code.
评论 #19904588 未加载
kartanabout 6 years ago
The article knowledge has been lost to time. In &quot;relational databases&quot; you always name the foreign key as the relationship between tables.<p>From &quot;A Practical Guide to Relational Database Design&quot; from the year 2000. &quot;Each relationship line should carry a pair of descriptive elements, which define the nature of the association between entities. A name is a single word or descriptive phrase; it should always contain a verb such as: owns, owned by, holds, administered by, etc. Examples from our simple model are: A PART is sold on an ORDER LINE. An ORDER LINE is placed for a PART.&quot;<p>But, this has been lost because the practicality is that it is hard to know what is the element. As other comments points.<p>Probably the best is both worlds: PersonId_Owner. PersonId_Veterinary. Or something similar.<p>It seems that such a discussion should have been solved decades ago. And here we are. :)
rhackerabout 6 years ago
I feel like the author has never used graphql. We&#x27;re also just finally graduating past REST to something more meaningful. This advice feels 15 years late and now totally wrong. An API shouldn&#x27;t be tied to a protocol like http, it should be able to move on to other things.<p>Ahh I was correct:<p>&gt; I have never used GraphQL, so I can&#x27;t endorse it, but you may want to evaluate it as an alternative to designing and implementing your own API query capability.<p>You really shouldn&#x27;t write this giant article without having tried that.
chvidabout 6 years ago
Hypermedia As The Engine Of Application State (HATEOAS)<p><a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HATEOAS" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HATEOAS</a><p>The idea has been around for a while; I personally don&#x27;t think it is a good idea.<p>There is even a content type (or two) for it: application&#x2F;hal+json and application&#x2F;hal+xml.<p><a href="http:&#x2F;&#x2F;stateless.co&#x2F;hal_specification.html" rel="nofollow">http:&#x2F;&#x2F;stateless.co&#x2F;hal_specification.html</a>
评论 #19890454 未加载
评论 #19890645 未加载
sisciaabout 6 years ago
I just don&#x27;t understand why mixing two different concepts at two different abstraction levels only for some, apparent, simplicity.<p>On one level we got ID unique identifier of a resource, on another level we have URL, how to get a specific resources.<p>They are just different things that shouldn&#x27;t be mixed.<p>What if tomorrow I want to get the same resource via graphql? Or in a message bus?
评论 #19890387 未加载
评论 #19890374 未加载
EugeneOZabout 6 years ago
What is the source of knowledge for the client about fields, where they can read link to the entity?<p>For human it&#x27;s obvious that dog has an owner, so field &quot;owner&quot; should be used, but for code - you need to write it, &quot;document it&quot;. So if you&#x27;re going to &quot;document&quot; every field containing link to external resource, you&#x27;ll end up with even more code, than just &quot;documenting&quot; API endpoints.<p>Also, pretty often you need multiple IDs of entities to send POST&#x2F;PUT request - just to create a relation.<p>POST &#x2F;adoption, owner_id=5, dog_id=7.<p>How should it look with links? Will it be issue for the server to parse them? And it&#x27;s just simple case with 1 to 1 relation, sometimes you need to add sets of objects to another entity.<p>It&#x27;s a really bad advice and after reading this I&#x27;m not sure I should trust other articles from that source.
评论 #19893835 未加载
kabesabout 6 years ago
The document also forgets that API&#x27;s are not read-only. So let&#x27;s say you have users and usergroups and you can request a usergroup with its list of users and you can add users to usergroups.<p>If you use links for read, you should also use them for writes, otherwise it&#x27;s quite inconsistent. So now you need to add a lot of parsing everywhere to extract the id&#x27;s out of the urls, just for the sake of being more dogmatic
评论 #19905303 未加载
评论 #19893602 未加载
whackabout 6 years ago
I&#x27;ve literally spent 2 years working on a project that did exactly what this article is recommending. There were some places which needed the relative-url as an identifier, and other places which needed the &quot;database id&quot; as the identifier. We constantly had to extract the id from the URL, or convert the id into a URL, and keep a mental map of which format each input was using, and which format was needed for each output. It was a mess. I would personally not recommended this at all.
评论 #19903591 未加载
评论 #19895790 未加载
wvenableabout 6 years ago
The caveats section of this article is longer than the content -- it makes a better case for <i>not</i> using links as keys.
anbopabout 6 years ago
Basically, advocating for dynamic typing rather than static typing, across an API boundary. You’ll save code constructing API requests but need to create a lot of application logic to handle an owner link and pet link separately, since they have different semantics.
gridlockdabout 6 years ago
No.<p>What&#x27;s the point? None of this is useful to me, all of this is extra complexity. Why would I want to expose every addressable entity through URLs and HTTP? That&#x27;s not what IDs are for.<p>I&#x27;m aware that this fits into the whole REST idea. I still don&#x27;t care.
austincheneyabout 6 years ago
I am surprised the article didn&#x27;t mention RDF. In every data facet of RDF the data is uniquely identified by URI. In the case of RDF the URI is merely a unique identifier that can resolve to a HTTP resource, but doesn&#x27;t have to.
vasilakisfilabout 6 years ago
The fact that JSON is just a format standard and doesn&#x27;t have specified components (like links etc) but instead we have to built those on top has cost us a lot in APIs. Btw, according to RFC 8288 Web Linking (and before that 5988), a link consists of 3 parts + 1 optional part:<p>&quot;In this specification, a link is a typed connection between two resources and is comprised of:<p><pre><code> o a link context, o a link relation type (Section 2.1), o a link target, and o optionally, target attributes (Section 2.2). A link can be viewed as a statement of the form &quot;link context has a link relation type resource at link target, which has target attributes&quot;. For example, &quot;https:&#x2F;&#x2F;www.example.com&#x2F;&quot; has a &quot;canonical&quot; resource at &quot;https:&#x2F;&#x2F;example.com&quot;, which has a &quot;type&quot; of &quot;text&#x2F;html&quot;.</code></pre> &quot;<p>That&#x27;s why you need a standardized link component that is globally accepted&#x2F;understood that takes into account all parts of the linking, instead of having various ways depending on the API&#x2F;JSON-based Media Type to communicate that something is a link.
评论 #19890898 未加载
vbezhenarabout 6 years ago
I used links but I&#x27;m gonna rewrite this code to simply pass IDs. The reason is simple: I need additional configuration for my server to know its hostname and I don&#x27;t want to do that. May be my server even have few different hostnames for different clients? So I must parse client request and extract Hostname? But it&#x27;s served via reverse-proxy, so I must do some complex configurations to pass this information. So many issues. But client knows perfectly well which server he&#x27;s talking to, so he can just append server-base and id. Yes, client must know about its structure, but it&#x27;s nonsense that client can somehow learn something. I&#x27;ll code that anyway.<p>May be it makes sense when you&#x27;re writing an API and some different person writes a client and she&#x27;s so shy that she don&#x27;t want to even ask you. Yeah, she can inspect answer and find out that this seems like a link to query further. I never was in that situation, I was always building all software myself, so for me this does not make sense.
theptipabout 6 years ago
I&#x27;m not sure about the verdict on URL versioning. I&#x27;ve used header versioning extensively and while flexible, it also carries some big downsides, mainly that it&#x27;s confusing for new developers, and makes it real hard to casually explore the API in a browser (bad DX). I&#x27;m also not sure you do want to encourage mixing v1 and v2 API representations; I have certainly seen cases where it makes progressive upgrade easier, but it can also bring inconsistencies, so having a default new integrator path of &quot;start at v2&#x2F;login and use whatever links you get&quot; is appealing.<p>I do like the idea from Stripe of having Accept header versioning, but pinning every new client to default to the newest GA version. Gets around most of the DX concerns I raised, but it&#x27;s a bit more machinery to wire up.
perfunctoryabout 6 years ago
One advantage I see is that now you can do<p><pre><code> &#x2F;pets?owner=&#x2F;people&#x2F;98765 or &#x2F;pets?owner=&#x2F;org&#x2F;98765 </code></pre> which makes your api more polymorphic.<p>Having said that I don&#x27;t think URL is the right term to describe this. It&#x27;s more like a &lt;type, id&gt; tuple.
miguelmotaabout 6 years ago
I wasn&#x27;t fully convinced by this article. Language specific API wrapper clients can abstract all these complexities. Having links for IDs felt very unnatural but I guess that&#x27;s because I have never came across an API that uses links like the article suggested
asavinovabout 6 years ago
Conceptual and data modeling aspects of this problem are discussed in [1]. It compares links with joins (and foreign keys) by proposing a solution (concept-oriented model) which does not use joins at all but rather relies on links only.<p>Essentially, a foreign key is viewed as a relational workaround for representing links with some significant drawbacks and the question is why not to use links directly without relational wrapping.<p>[1] Joins vs. Links or Relational Join Considered Harmful: <a href="https:&#x2F;&#x2F;www.researchgate.net&#x2F;publication&#x2F;301764816_Joins_vs_Links_or_Relational_Join_Considered_Harmful" rel="nofollow">https:&#x2F;&#x2F;www.researchgate.net&#x2F;publication&#x2F;301764816_Joins_vs_...</a>
评论 #19891170 未加载
gigatexalabout 6 years ago
Sometimes I wish REStful&#x2F;REST the whole idea was a lot more opinionated. Sure you can have opinionated frameworks but nothing is stopping you from using a patch like I would a delete... (not the best example but you get the gist).
abetlenabout 6 years ago
I think the issue brought up in this blog post pales in comparison to the two biggest problems faced when working with REST APIs: querying for nested data, and the limitations of CRUD interfaces to model complex behavior.
评论 #19892035 未加载
schnableabout 6 years ago
How do you write the article and never mention REST, hypermedia or HATEOS once?
评论 #19905439 未加载
i386about 6 years ago
Why on earth would you blow out your request size for the sake of purity? Calling GET &#x2F;pets is going to return a lot of instances of pet with very similar URLs.
currriuoslyabout 6 years ago
This is what Django REST framework had done right for years.
评论 #19890417 未加载
hit8runabout 6 years ago
JSONAPI Specification also makes use of URLs in links to resources:<p><a href="https:&#x2F;&#x2F;jsonapi.org" rel="nofollow">https:&#x2F;&#x2F;jsonapi.org</a>
评论 #19895831 未加载
vbstevenabout 6 years ago
What really convinced me about HATEOAS and links was the first time I used a HAL browser and started clicking around to discover an API using only its entry point and navigating from there.<p>From that point on I try to use it as much as possible. A typical API response for my projects looks like this:<p><pre><code> { &quot;id&quot;: &quot;3ccf0f1b-dd3f-48d9-911a-ddf479078c37&quot;, &quot;name&quot;: &quot;Quantus Tasks&quot;, &quot;description&quot;: &quot;Quantus Tasks Desktop Application&quot;, &quot;license_key_type&quot;: &quot;alphanumeric_32&quot;, &quot;created_at&quot;: &quot;2019-05-12T10:45:42.089406Z&quot;, &quot;updated_at&quot;: &quot;2019-05-12T10:45:42.089406Z&quot;, &quot;_links&quot;: { &quot;self&quot;: { &quot;href&quot;: &quot;http:&#x2F;&#x2F;localhost:8000&#x2F;v1&#x2F;applications&#x2F;3ccf0f1b-dd3f-48d9-911a-ddf479078c37&quot; }, &quot;licenses&quot;: { &quot;href&quot;: &quot;http:&#x2F;&#x2F;localhost:8000&#x2F;v1&#x2F;applications&#x2F;3ccf0f1b-dd3f-48d9-911a-ddf479078c37&#x2F;licenses&quot; }, &quot;templates&quot;: { &quot;href&quot;: &quot;http:&#x2F;&#x2F;localhost:8000&#x2F;v1&#x2F;applications&#x2F;3ccf0f1b-dd3f-48d9-911a-ddf479078c37&#x2F;templates&quot; }, &quot;apikeys&quot;: { &quot;href&quot;: &quot;http:&#x2F;&#x2F;localhost:8000&#x2F;v1&#x2F;applications&#x2F;3ccf0f1b-dd3f-48d9-911a-ddf479078c37&#x2F;apikeys&quot; } } } </code></pre> It still has the ID field in there for cases where the client needs to store the id itself but it should not be used to template URI&#x27;s for related resources, the links are there for that.
评论 #19891404 未加载
sam0x17about 6 years ago
I think I am missing the core concept here. This still uses IDs, only now you have to grep them out of a URL construct instead of just getting them directly?<p>I don&#x27;t get the intent at all here, but I have a suspicion whatever problem this tries to solve is better solved by UUIDs or by doing nothing out of the ordinary.
评论 #19892057 未加载
ragerinoabout 6 years ago
Reminds me of HATEOAS see here: <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HATEOAS" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;HATEOAS</a><p>Also RDF endpoints usually use resolvable URI&#x27;s to connect concepts and objects with each other.
polskibusabout 6 years ago
Is the main reason for this is that crawlers could figure out and index more by themselves?
tveitaabout 6 years ago
No one thinks twice about using links for images. You wouldn&#x27;t make an API that specified images as &quot;image id 2345, which the client can find at &#x2F;images&#x2F;{id}&quot;
评论 #19892998 未加载
coding123about 6 years ago
This is all assuming REST is still a good idea.
carmate383about 6 years ago
Why on earth would one trade off a short, static unique identifier for a potentially long, dynamic &quot;link&quot; that essentially binds all data to some crappy API that will be outdated in a few years? Is it really _that_ hard to use keys?
the_arunabout 6 years ago
In micro services world this makes perfect sense. In the legacy land - this is slightly tricky as dependent application (where our foreign key points to) may or may not be in services world. But I get the idea.
评论 #19895878 未加载