Live data from Hacker News

API Design Guide

cloud.google.com

171–180 of 192 posts

Re: API Design Guide

#171
post #116

They didn't mention one very important thing - querying only required data and making connections between resources. For example, you need to download some git commits with user profiles. User is a different resource than git repo. How we can request such data in one single request? Then you will need also to load referenced issues (if present) that is implemented as different resource. GraphQL solve this problems in…

Neither side supports the case of [promise chaining](https://capnproto.org/rpc.html), where one or more resources can be used to look up further resources in a single round trip. Each style has tradeoffs.

Re: API Design Guide

#172
post #12

I would like to add Microsoft's API Guidelines [1] here, which is also a well written document and can be helpful to anyone designing an API. [1]: https://github.com/Microsoft/api-guidelines/blob/master/Guid...

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.

As I see it, HATEOAS by providing API structure dynamically depending on application state, restricts the application to non-concurrent use and full backward compatibility, because application state perceived by the client and the actual state might diverge in concurrent use (either concurrent clients or state change by code upgrade). It is impossible to build a client (which does more than query a resource in a loop and simultaneously does the right thing) that will magically know about newly available link if application state changes between getting the resource, making a decision and following a link based on that decision. Which clearly breaks the very intent to make the API self documenting.

Taking Wikipedia example [1], how can a client know whether the application stopped supporting withdrawals altogether (it is dynamic after all) or is it the particular account it is querying? What happens when account is overdrawn between a client querying state and attempting a withdraw? When should a client stop expecting returned endpoint to be still available? How do you document possible outcomes?

Another example of HATEOAS not being thought through is the self link. If a client is querying application through proxy (e.g. forwarded port to directly unreachable destination or some kind of aggregator application), the self link becomes incorrect. Should a client know to magically rewrite the link or treat it as a redirection? If the application is reachable by various paths (domain names, IPs) it must know the path client took, to return correct self link even without a proxy.

HATEOAS restricts application to a set of very specific use cases with subtle traps to fall into. I see no way to avoid both these traps and need for documentation, which, in my view, defeats the purpose. Your mileage may of course vary.

[1]: https://en.wikipedia.org/wiki/HATEOAS

Re: API Design Guide

#173

on a related note, anyone know a good saas for api documentation? preferably one that could take jsdoc imports or other code based generated docs...

I'm not sure exactly what you are looking for but try this tool from the swagger people:

http://editor.swagger.io/#/

It gets a little laggy for large swagger docs but its' quick and easy for smaller API docs.

Re: API Design Guide

#174

Earlier quoted context omitted.

As described in https://cloud.google.com/apis/design/design_patterns#get_uni... : //calendar.googleapis.com/users/-/events/123

Hadn't spotted that, it's an interesting syntax and I quite like it. But it doesn't cover the case I'm referring to; in their example you MUST return the fully-qualified URL: > shelves/shelf713/books/book8141, not shelves/-/books/book8141 This precludes there being multiple shelves with the same book (sensible in their example, since a book has only one shelf, but not in the example above).

While sometimes this does get tricky with resources that are clearly owned or associated with multiple things, often times a resource only has one real owner and it is unambiguous. It does make moving things a bit weird though, as moving a book between two shelves makes it have a different fully qualified name.

Re: API Design Guide

#175

Earlier quoted context omitted.

This is an API guideline, not a strict REST one. Also it has become very clear to me everyone has a different interpretation of what REST can or should be. We all are quick to forget that the actual acronym stands for "representational state transfer" which is an abstract concept and therefore can be implemented in many, many different ways.

It's heavy 'REST' oriented. A Java guideline for API's would like completely different.

The guide actually explicitly says it is focused on gRPC.

Re: API Design Guide

#176
post #61

What is current consensus on client libraries? Braintree for example requires that you use their client libraries where as Stripe makes them optional. With Google's gRPC thing I can definitely understand using libraries for performance. Otherwise, isn't making simple REST calls without custom libraries sufficient for most uses? Or if you want a library, something generic like Unirest [1]? 1. http://unirest.io/

If your REST API is documented in OpenAPI/Swagger spec, then you can use Swagger Codegen [1] to generate API clients (Java, C#, PHP, etc), server stubs (e.g. C# NancyFx, PHP Lumen, Python Flask, etc) and API documentations.

[1] https://github.com/swagger-api/swagger-codegen

Re: API Design Guide

#177
post #158
post #134

Earlier quoted context omitted.

Just guessing, if you had an API for creating documents for example, and you POST a request to /docs/ you'd get back not an just a single ID but a URL to /docs/ . So then the client can operate on that resource and not have to compose it. It can also be browse-able with a regular browser. If you visit it say with Firefox and go to .../api/ and the browser tells the backend it accepts text/html back, the service would…

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 generate the new base URL `/cool_users/`. This means you'll need to version your API, so that old clients can continue to access the old-style endpoints in the transition period. (Note that for a business where your customers are making an API integration, this means you're imposing work on your customers).

With HATEOAS, you just need to update the URLs that are returned in your other endpoints. (Generally there is one well-known entry-point into your API, e.g. you return {"user_list": "/users/", ...} with your login token, for example). Now, assuming your clients were using `api.user_list`, that they received, they will without further modification fetch the `/cool_users/` endpoint, without requiring an update.

The one gotcha is if clients are holding on to the IDs of your API objects between API calls; in that case, you will break any code which expects to find those previously-returned members. But note, the worst-case here is that you need to version your APIs, which was the best-case without HATEOAS. In many cases you can get away with such a change without any client-facing changes.

Re: API Design Guide

#178

Earlier quoted context omitted.

Hadn't spotted that, it's an interesting syntax and I quite like it. But it doesn't cover the case I'm referring to; in their example you MUST return the fully-qualified URL: > shelves/shelf713/books/book8141, not shelves/-/books/book8141 This precludes there being multiple shelves with the same book (sensible in their example, since a book has only one shelf, but not in the example above).

While sometimes this does get tricky with resources that are clearly owned or associated with multiple things, often times a resource only has one real owner and it is unambiguous. It does make moving things a bit weird though, as moving a book between two shelves makes it have a different fully qualified name.

Agree; put another way, sometimes you really do need a M2M relationship.

Re: API Design Guide

#179

An interesting design question arrises around nested resources. Google in this doc buys into deep nested structures, e.g. `//calendar.googleapis.com/users/john smith/events/123` (from [1]). I think this pattern is unambiguously sensible when the child objects are strictly scoped under the parent. But it's less clear how to represent resources that are shared between multiple parents; for example, what if event 123 ca…

I prefer the bare minimum approach. That is, if you NEED the user resource to access the event (eg the primary key is like [user ID, event ID]) then nest it in the url. Otherwise if an object has its own ID and could otherwise be accessed independently why not just do so?

The root of this question is: how do you handle M2M relationships in your API?

Re: API Design Guide

#180

Earlier quoted context omitted.

I wrote about API design (with a similar rejection of HATEOAS): http://www.vinaysahni.com/best-practices-for-a-pragmatic-res... In short: humans can follow links, even as a website goes through significant changes. Code can follow links, but can't make clear independent decisions when significant changes happen to the API. [Updated for clarity]

Thank you for your write-up on API design. It's well-written, concise and to the point. I spent quite some time reading it while learning best practices about REST API design last year.

I'm happy the post helped you :)
Post reply on HN