Live data from Hacker News

API Design Guide

cloud.google.com

181–190 of 192 posts

Re: API Design Guide

#181
post #109

Earlier quoted context omitted.

It's just never been clear to me what HATEOAS is really supposed to be good for. Sure, a client can follow the links in an automated fashion, but how is it supposed to know what the resources actually are and which links it needs to follow, which resources it has to create or modify, to actually accomplish anything? The general idea of returning links to related resources and/or actions is fine and good, but the rhet…

To me the best advantage is that by following links, the client doesn't have to builds those links in the first place. So the client will keep working even if a few months from now you want to change the link to something else. A simple example: if retrieving articles can be done by requesting this link "/articles", I can potentially change it in the future to "/v2/articles" and the client would still work.

The client may not have to build the links but it still has to be aware of their specifics. It has to know that /articles takes arguments X and Y, and that /v2/articles takes arguments Y and Z. You're trading building links to inspecting links. What advantages does this have?

Re: API Design Guide

#182

Do any of these API guides have good guidance around batch endpoints like handling a PATCH on multiple resources as a single request?

I've used two strategies:

1. If it's a transaction (all-or-nothing) I POST a new transaction resource which references all the target resources. Remember that you can create as many resources as you want. There is no need to have a 1:1 mapping between your resources and the database.

2. If it's a batch statement (some-can-fail-some-can-lose) I simply stick to issuing multiple requests. This frees me and my clients from having to write complicated code that deal with partial success - and it can still be very fast especially with request pipelining.

If issuing multiple statements is too slow then I would attempt to increase the speed of the stack before adding the complexity of having to deal with partial success.

So in conclusion... No really good ideas on how to write batch statements. I don't really think REST APIs with their one HTTP response code maps very well for that use case. But I hope one of the two strategies above will be useful to you.

Re: API Design Guide

#183
post #73

Earlier quoted context omitted.

How is: { "@context": "http://json-ld.org/contexts/person.jsonld", "@id": "http://dbpedia.org/resource/John_Lennon", "name": "John Lennon", "born": "1940-10-09", "spouse": "http://dbpedia.org/resource/Cynthia_Lennon" } Better than: (http://json-ld.org/contexts/person (id http://dbpedia.org/resource/John_Lennon) (name "John Lennon") (born 1940-10-09) (spouse http://dbpedia.org/resource/Cynthia_Lennon)) Note that the l…

The answer to that is really simple: JSON is a widely supported standard in many platforms and languages. Whatever the latter is, is not. What's better than writing a parser for the latter format, is not having to write anything and just using a library, which exists in practically every language for JSON.

Ever heard of LISP, or S-expressions?

Re: API Design Guide

#184

Earlier quoted context omitted.

You can find smarter clients by Googling "hypermedia client". Also, O'Reilly just published a book on the topic: http://shop.oreilly.com/product/0636920037958.do

But would anybody really want to use a hypermedia client versus a regular client? Of course not. The regular client can be optimized properly at the level it needs to be to make the user's interaction smoother.

You are entering your comment into a general purpose hypermedia client for humans, why wouldn't you want a general purpose client for machines?

Re: API Design Guide

#185

Earlier quoted context omitted.

The answer to that is really simple: JSON is a widely supported standard in many platforms and languages. Whatever the latter is, is not. What's better than writing a parser for the latter format, is not having to write anything and just using a library, which exists in practically every language for JSON.

Ever heard of LISP, or S-expressions?

Of course, I even write some hobby projects in Common Lisp.

There are data interchange formats that use S-Expressions, namely EDN[1]. But JSON remains the most popular format for its widespread support, and its few data types map to most languages.

[1]: https://github.com/edn-format/edn

Re: API Design Guide

#186
post #12

Earlier quoted context omitted.

It's interesting that both of these guidelines kind of reject HATEOAS by mandating explicit versioning. It seems that HATEOAS was never really a thing. It's just too complicated to implement in practice. In that sense, REST in practice has always been just RPC without a clear spec for procedure call like XML or JSON RPC.

It's just never been clear to me what HATEOAS is really supposed to be good for. Sure, a client can follow the links in an automated fashion, but how is it supposed to know what the resources actually are and which links it needs to follow, which resources it has to create or modify, to actually accomplish anything? The general idea of returning links to related resources and/or actions is fine and good, but the rhet…

Use something like JSON-LD, where the payload contains hyperlinks to documents for each data property.

Your client then can machine read that documentation (which can have long-lived cache headers or be immutable, so your client doesn't spend it's whole time re-checking documentation).

There will be a set of definitions that the client understood when it was coded, and by checking a payload for matching meanings, it can consume the information.

If it finds something it doesn't understand, it could even try to take some compensating action (e.g. suppose it's a client which displays images to it's users, and it encounters a new type of image format. It could perhaps look up a registry of javascript canvas image renderers and download suitable code to display the new image).

Re: API Design Guide

#187
post #158

Earlier quoted context omitted.

If you get back an URL to the document instead of the ID, then whenever you need to refer to that document, you need the whole URL. That means that it can't change, which I thought was one of the arguments for using HATEOAS, that you don't need to hardcode the URLs, and can "evolve" the API without breaking clients.

This is a point which is I think overplayed by HATEOAS fans and under-appreciated by HATEOAS haters; using URLs as IDs makes it easier to evolve the API in many cases, but it doesn't make it completely painless to do so. If you have an object which links to `/users/1/`, and want to change that URL to `/cool_users/1/`, what's the migration path? Without HATEOAS, you need to update all your clients' code to now generat…

Yes, correct. However, this relies on clients using your API in a hateos way - which they have to go out of their way to do: starting at /, reading the responses, navigating down only using URLs that you return, etc...

No clients bother to do this, in the real world - they just hard code/compose the URLs that they need to use. Why make extra http calls when you don't have to? Why parse all the json-hal (or whatever) to "figure out" which URL to call next, when you don't have to?

Even if most clients did this, you can't enforce it, so not all of them will, so some will still break when you change URLs.

Re: API Design Guide

#188
post #187

Earlier quoted context omitted.

This is a point which is I think overplayed by HATEOAS fans and under-appreciated by HATEOAS haters; using URLs as IDs makes it easier to evolve the API in many cases, but it doesn't make it completely painless to do so. If you have an object which links to `/users/1/`, and want to change that URL to `/cool_users/1/`, what's the migration path? Without HATEOAS, you need to update all your clients' code to now generat…

Yes, correct. However, this relies on clients using your API in a hateos way - which they have to go out of their way to do: starting at /, reading the responses, navigating down only using URLs that you return, etc... No clients bother to do this, in the real world - they just hard code/compose the URLs that they need to use. Why make extra http calls when you don't have to? Why parse all the json-hal (or whatever)…

This is why my HATEOAS APIs always return urls in the form "https://mysite.com/{SHA256 hash}", and a façade API looks up the actual path from the cached hash. Hardcode that, bitches.

Re: API Design Guide

#189
post #187

Earlier quoted context omitted.

This is a point which is I think overplayed by HATEOAS fans and under-appreciated by HATEOAS haters; using URLs as IDs makes it easier to evolve the API in many cases, but it doesn't make it completely painless to do so. If you have an object which links to `/users/1/`, and want to change that URL to `/cool_users/1/`, what's the migration path? Without HATEOAS, you need to update all your clients' code to now generat…

Yes, correct. However, this relies on clients using your API in a hateos way - which they have to go out of their way to do: starting at /, reading the responses, navigating down only using URLs that you return, etc... No clients bother to do this, in the real world - they just hard code/compose the URLs that they need to use. Why make extra http calls when you don't have to? Why parse all the json-hal (or whatever)…

Very true - that is the best counterargument. However, we're still back to the worst-case here being the best case without HATEOAS, and well-behaved clients can still reap the benefits even if there are some misbehaving clients requiring multiple versions to be deployed in parallel.

There's a good question about how long you can cache those URLs for as well; it's a non-starter for a client to have to traverse the whole tree from the root for every request. So can I cache the responses for the duration of my auth token, and get a new root node as part of my re-auth?

If you go down that route, now you need to maintain two versions again during migration (but you do keep the ability for 'well-behaved' clients to migrate versions without downtime).

As the sibling comment describes, you _can_ enforce this by obfuscating your URLs, but I've not had the guts to do that yet...

Another approach would be to write great client libraries yourself, so that you know that the clients are consuming the API correctly.

Re: API Design Guide

#190
post #188
post #187

Earlier quoted context omitted.

Yes, correct. However, this relies on clients using your API in a hateos way - which they have to go out of their way to do: starting at /, reading the responses, navigating down only using URLs that you return, etc... No clients bother to do this, in the real world - they just hard code/compose the URLs that they need to use. Why make extra http calls when you don't have to? Why parse all the json-hal (or whatever)…

This is why my HATEOAS APIs always return urls in the form " https://mysite.com/{SHA256 hash}", and a façade API looks up the actual path from the cached hash. Hardcode that , bitches.

Haha, I have definitely considered that path, but

1) It makes manual testing annoying, 2) I have a nagging feeling that if my users are "doing it wrong" then maybe the API is doing it wrong...

Also I've been playing with autogenerating client implementations using autogenerated swagger specs, and that approach is incompatible with an actual opaque linked API. It would be nice to have the best of both worlds.

Post reply on HN