News for hackers. Stuff that matters.
Re:Use links not keys to represent relationships in APIs by twblalock on Sunday May 12, 2019 @02:51AM (#19890556)
Here is the problem with links in a nutshell:

> 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).

If you have to honor all previously-issued URLs then you aren't changing your format -- you are supporting two formats from now on, the old one and the new one.

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.

If the URLs in your API responses are FQDNs rather than relative paths, all of this gets significantly harder to deal with.

Even if you figured all of that out, links are not idiomatic if your users consume your api via an RPC or GraphQL.

Re:Use links not keys to represent relationships in APIs by ljm on Sunday May 12, 2019 @01:04PM (#19893049)
If I had to choose I'd used Stripe and Protobuf for inspiration.

Stripe uses a date as its version and it maintains state for each user, so it knows whether to serve an old version or latest and greatest. They offer UI and tools to manually migrate to a new version, with clear expectations and changelogs provided. They can build a rollout and sunset plan around that.

Protobuf is append only until you change the actual package. This gives you the opportunity to make additive changes without making a breaking change and you don't need to maintain separate releases as you make incremental updates or bug fixes. If the API changes significantly, it's no longer the same API, it's a new one.

Re:Use links not keys to represent relationships in APIs by mpnally on Monday May 13, 2019 @12:00PM (#19900595)
JSON works this way too. This deals with how to deal with the evolution of the data associated with an entity, it does concern the identifiers.
Re:Use links not keys to represent relationships in APIs by bruth on Sunday May 12, 2019 @05:51AM (#19891015)
This argument is true for any data that was included in the response. If the client chooses to cache it, it needs to deal with it being stale.. which in this case could result in a 404. Obviously it would be a nice-to-have if the server had a redirect from the old to new.

> Even if you figured all of that out, links are not idiomatic if your users consume your api via an RPC or GraphQL.

Agreed, although you could model a link in the object-based structure representation to match the protocol, something like..

  # RPC
  {
    "rel": "owner",
    "procedure": "GetOwner",
    "args": {
      "id": 98765
    }
  }

  # GraphQL
  {
    "rel": "owner",
    "root": "owner",
    "args": {
      "id": 98765
    }
  }
Re:Use links not keys to represent relationships in APIs by jayd16 on Sunday May 12, 2019 @04:21AM (#19890797)
>(of course, the server must continue to honor all previously-issued URLs).

Why is this true for non-user facing urls? Seems like an argument could be made that you only need to support the urls for as long as the response was cacheable.

Re:Use links not keys to represent relationships in APIs by emn13 on Sunday May 12, 2019 @05:29AM (#19890958)
And the problem isn't really limited to links in the response; the same goes for computed links based on keys too.

In fact, links in responses are probably easier to update, because waiting for client software to upgrade can take a long time - but waiting for old versions to fall out of caches or at least dwindle to a small enough number is likely a much shorter wait.

Furthermore, when your clients are composing links based on keys, there's no good way for the server to tell a client that the uri has changed - the composition is in the client, and the key (presumably) hasn't changed, so the thing the server would want to update is out of conventional reach.

But with uri's there's at least a conventional solution - redirects. That's not going to be an ideal solution; but as a way of limiting transition pain it might have a place.

All in all, I think links are likely less painful to use than keys when it comes to uri routing changes. (But really, try to avoid changing uri's in the first place, because whatever you do it's likely going to be painful somewhere).

Re:Use links not keys to represent relationships in APIs by barrkel on Sunday May 12, 2019 @05:31AM (#19890962)
It's an API. The client isn't likely to be a browser. If it's integrating with another system, those links may have quite a long life.
Re:Use links not keys to represent relationships in APIs by randallsquared on Sunday May 12, 2019 @09:14AM (#19891663)
Caching behavior is not only about browsers.
Re:Use links not keys to represent relationships in APIs by barrkel on Sunday May 12, 2019 @09:49AM (#19891872)
For sure, but for most people using APIs to integrate with systems, caching is an unwanted middle way between always fresh and stored persistent, where local storage is the "cache", except it isn't invalidated using HTTP logic.
Re:Use links not keys to represent relationships in APIs by jayd16 on Sunday May 12, 2019 @06:21PM (#19894955)
>except it isn't invalidated using HTTP logic.

You should be doing this. It helps a lot, actually.

Re:Use links not keys to represent relationships in APIs by mpnally on Monday May 13, 2019 @11:14AM (#19900076)
Cache timeout limits generally apply to the data retrieved for a URL, not the URL. If you know that your clients will never "bookmark" or in any way store URLs, then you can change them. The same rule applies for all identifiers, not just URLs
Re:Use links not keys to represent relationships in APIs by smadge on Sunday May 12, 2019 @05:31AM (#19890963)
I don’t think we should follow a 2 decade old thesis dogmatically, but I would point out that Roy Fielding has said:

“A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types“

In this case the only URL that is support long term is the entry point into the application. All other resources are discoverable from the index.

Re:Use links not keys to represent relationships in APIs by bartread on Sunday May 12, 2019 @05:47AM (#19891005)
This really is an old quote, and some people certainly do cling to it quite dogmatically, but my own experience suggests that slavishly following this principle makes life more difficult for both producers and consumers, and that there's little substitute for excellent API documentation, and clear, timely communication of changes.
Re:Use links not keys to represent relationships in APIs by mpnally on Monday May 13, 2019 @11:16AM (#19900100)
I don't think Fielding meant to say that you cannot bookmark a URL, which is what your interpretation would imply. He was only commenting on how you find the URL in the first place to bookmark it.
Re:Use links not keys to represent relationships in APIs by imtringued on Monday May 13, 2019 @06:23AM (#19897772)
REST isn't SOAP. What you're describing just adds unnecessary complexity.
Re:Use links not keys to represent relationships in APIs by lugg on Sunday May 12, 2019 @05:44AM (#19890998)
No half decent programmer will randomly break backwards compatibility anyway so I'm not sure what your point is.

Consider your audience. Is it APIs like GitHub? Well guess what, you're stuck with maintaining backwards compat anyway, may as well have the relationships readable.

And if it's not and you control both ends then what does it matter because you can break links all you want.

It was touched on but less emphasized the relationships being expressed as links exposes further context than you otherwise get.

It's also nice to be able reason about shared domains. I.e. you might have the concept of a stock item and an order item. They are both represent the same thing in the real world and share a lot of information but depending on the value of self will tell you what kind of data you can expect to be a available and what domain you're in as well. Reading logs would be oh so much clearer.

Re:Use links not keys to represent relationships in APIs by mooreds on Sunday May 12, 2019 @09:35AM (#19891788)
I always enjoy this article from 2017 about how to version complex large old APIs.

https://stripe.com/blog/api-versioning

Re:Use links not keys to represent relationships in APIs by asavinov on Sunday May 12, 2019 @08:29AM (#19891490)
From the conceptual modeling point of view it is important to understand that:

(1) There can be several levels of entity identifiers, that is the same entity exists at several levels where it has different identifiers. Example: a computer has DNS name and IP address (and MAC address); a person may have several identifiers. These (initially independent) spaces can be structured differently:

(1.1) Layered structure like DNS and IP (1.2) Independent, e.g., a person has two passports from different countries

(2) Links (representing relationships) are attributes. Like all attributes they are functions which map input entity identifiers into output (address) space identifiers.

Taking this into account, the problem is that URLs frequently play two roles, that is, one address convention is used at two layers simultaneously which can lead to numerous problems and controversies:

o URLs are used at access (protocol) level where the goal is to identify computers and access paths within some service (and not entity). For example, this layer has no idea what this means: http://service.com/passports/1234 - it is used for HTTP access only.

o URLs are used to identify real entities and here we re-use the previous name convention for higher level purposes by identifying people like http://service.com/passports/1234 although we do not care about protocols or computer names.

In order to avoid serious problems we need to follow these steps:

* Recognize and document that there are two independent address spaces

* Define a mapping between these two spaces. Initially, it can be identity relationship, that is, every entity name (URL) is mapped to the same URL used for access.

* If necessary (and frequently highly desirable) use relative names by assuming that the higher level segments of the name can be restored from the context or configured separately.

These rules are especially important for extensibility and for complex evolving systems where the standards and conventions change in time.

Re:Use links not keys to represent relationships in APIs by dragonwriter on Sunday May 12, 2019 @05:36AM (#19890973)
> If you have to honor all previously-issued URL

You don't have to honor it forever; if you want to be good about planning for changes, you annotate each link with the latest date when it is guaranteed not to be expired, and the latest date an updated authoritative URL will be available (either as content in the resource representation or an HTTP redirect) if it expires on the earliest possible date. Consumers are then free to determine whether they need to update links or whether the data from which they come is stale (if your resources at any given link are immutable but for metadata about currency and links to updated versions if the content of the logical entity has changed, so that you can always recover the same version of an entity you fetched at the original URL so long as the URL hasn't expired, clients don't even need to check each references URL for updates, they can just check the base URLs of the entities they already have read that referenced them, and in the process update all referenced URLs; you kind of need that allow clients an approximately consistent view of data when they can't read it all simultaneously anyway, and if your API doesn't need that level of consistency, it then it certainly doesn't need link stability, either—you’ver already decided you are dealing with fundamentally ephemeral data,.so.if people don't follow links relatively quickly, they aren't getting meaningful data even if the links are permanently stable.)

Re:Use links not keys to represent relationships in APIs by bpicolo on Sunday May 12, 2019 @08:44AM (#19891545)
> you annotate each link with the latest date when it is guaranteed not to be expired

If I were paying someone for access to such an API, I would do everything in my power to change providers. Tracking link expiration would be a terrible developer experience. Such a thing may be a sound design for a system, but it's not a good design.

Providers like Twilio and Stripe have been largely successful because they've aimed for making developer experience as non-sadistic as possible.

Re:Use links not keys to represent relationships in APIs by jhayward on Sunday May 12, 2019 @09:31AM (#19891766)
Anyone who has maintained a database such as a customer database knows that it needs to be constantly tested and updated to track changes in e.g., telephone, email, billing, or delivery addresses.

What's different about this proposal? It would seem to acknowledge and support that type of activity directly, rather than through ad-hoc and kludge type mechanisms that typically include paying somewhat shady 3rd-party services.

Re:Use links not keys to represent relationships in APIs by skybrian on Sunday May 12, 2019 @01:54PM (#19893367)
Maybe the version could be in the hostname? Then site-relative URL's go to the same version you were using, which is presumably what you want. But I agree that it doesn't seem all that useful.

It seems like any of these schemes make assumptions that some things are invariant when switching to a new version, so you don't have to start over.

For example, if user IDs are just integers then you have a fairly conservative assumption that clients can store the user IDs and they can be reused with a new version. That is, users won't be renumbered. But everything else about the API can change between versions.

A site-relative URL also fixes part of the URL template between versions, so it can be safely stored. But the host can change.

I'm skeptical that URL's are all that helpful here. Why not do a POST using something like protobufs and avoid the issue entirely? An API like this is site-specific anyway and requires custom client code (other than the parsing layer which can be generated from a schema). It seems weird to pretend otherwise, as if some universal client existed. At best, you could use a browser for debugging, but that's about it.

Re:Use links not keys to represent relationships in APIs by ivanhoe on Sunday May 12, 2019 @07:56AM (#19891373)
True, but isn't it the same with the IDs? You still have the problem of honoring previously-issued URI templates when you change the format.
Re:Use links not keys to represent relationships in APIs by theptip on Sunday May 12, 2019 @12:13PM (#19892738)
This - and if your clients are getting their URLs from a downloaded swagger spec or even worse, from something they hardcoded, then the upgrade path is much worse with IDs.

With HATEOAS, at the best case is that clients just bump the entry point url (or even have it bumped for them) and then follow the links they are given. It's not possible to upgrade clients that way if they are constructing urls themselves.

Re:Use links not keys to represent relationships in APIs by bradleyjg on Sunday May 12, 2019 @11:23AM (#19892447)
Google seems almost pathologically allergic to maintaining backward compatibility in any context. Just doesn’t seem to be in their DNA. So it’s no surprise that advice originating from there doesn’t put much thought into how to maintain backward compatibility.
Re:Use links not keys to represent relationships in APIs by jon-wood on Sunday May 12, 2019 @12:21PM (#19892801)
I wonder if this is an artifact of their monorepo developer culture, where they allow only one version of a library in the whole repo, and changing APIs is something that can be applied across the entire codebase?
Re:Use links not keys to represent relationships in APIs by mpnally on Monday May 13, 2019 @11:57AM (#19900563)
Saying that URLs are not idiomatic with RPC or GraphQL is really just saying that most people aren't used to this way of thinking. Specifically, they are not used to is treating URLs as identifiers. Most programmers and API designers think of URLs as being a way of encoding remote procedure calls, with identifiers being parameters to the call that must be embedded inside the URL. The point of the blog was to try to explain why a minority of people like to use a different model where the URLs _are_ the identifiers.
Re:Use links not keys to represent relationships in APIs by zjs on Sunday May 12, 2019 @12:55PM (#19892981)
You don't necessarily need to support two formats; you need to support redirecting the previously-issued URLs. This _can_ be accomplished by supporting the old format, but it doesn't _need_ to be.

Instead, you could just use a database of redirects which you append to when you make format changes. For some applications, the overhead of maintaining a redirect service is far lower than trying to maintain support for multiple formats. (And this redirect service may even be something you need/want for other reasons.)

Re:Use links not keys to represent relationships in APIs by zepolen on Sunday May 12, 2019 @01:19PM (#19893153)
Redirecting doesn't work - your customer has an application expecting v1 format - and he gets a redirect to v2 which breaks his application.

I've found more success in supporting two formats using the v2 api to serve the v1 one.

Re:Use links not keys to represent relationships in APIs by joshuamorton on Sunday May 12, 2019 @03:40AM (#19890689)
The point here is that you can do this more easily. Consider a really dumb example

/people/12345 becoming /people/v2/12345

Sure, you still have to support the old version (maybe only temporarily), but migrating schemas gets marginally easier (you can do it via an entirely different service, for example)

Re:Use links not keys to represent relationships in APIs by macca321 on Thursday May 16, 2019 @11:20AM (#19929807)
You actually don't need to honour the links.

If a client gets a 410 when following a stored link, they can always find the new url for the resource by following links from the parent resource (this is recursive, all the way back to the root url).

Re:Use links not keys to represent relationships in APIs by carapace on Sunday May 12, 2019 @11:19AM (#19892423)
Re:Use links not keys to represent relationships in APIs by asaph on Sunday May 12, 2019 @11:24AM (#19892451)
You still have to keep deprecated URLs responsive in order to issue HTTP 301 redirects. And until 100% of legacy clients update their calling code (could be never), you can't remove support without breaking the system for legacy clients.
Re:Use links not keys to represent relationships in APIs by ddalex on Sunday May 12, 2019 @11:53AM (#19892637)
Yeah, but it doesn't mean you have to serve them from the same codebase. Partition the old urls to a thin service that only does the URL transcription and issues the 301 and you're done
Re:Use links not keys to represent relationships in APIs by carapace on Sunday May 12, 2019 @12:25PM (#19892837)
I'm thinking of moving some docs now, as it happens, and it looks like all I'll need to do to serve 301's for them is put a few lines in an .htaccess file.

My deeper point is that all this has been hashed out and settled by now. If you're still having this problem in 2019 you're either playing around or "Doing It Wrong".

Re:Use links not keys to represent relationships in APIs by asaph on Sunday May 12, 2019 @12:50PM (#19892959)
Another thing to keep in mind is that HTTP 301 redirects are typically only followed for GET requests. POST, PUT & DELETE requests will still be broken.
Re:Use links not keys to represent relationships in APIs by M2Ys4U on Sunday May 12, 2019 @06:23PM (#19894965)
That's what 308 is for
Re:Use links not keys to represent relationships in APIs by asaph on Sunday May 12, 2019 @07:56PM (#19895412)
Thanks. I never knew about the HTTP 308 response code. Here is the RFC dated June 2014:

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