Live data from Hacker News

API Practices If You Hate Your Customers

queue.acm.org

131–140 of 258 posts

Re: API Practices If You Hate Your Customers

#131
post #32

I was totally expecting to see something about using a protocol in an unexpected way, because "the protocol is not good enough". I had to work with an API where the company decided everything should return http code 200 (well, at least all 4XX errors), and give the error code in the JSON response, mixing existing 4XX errors and their own errors. When pointed out, the support answer was "we chose to give meaningful er…

> I had to work with an API where the company decided everything should return http code 200 (well, at least all 4XX errors), and give the error code in the JSON response, mixing existing 4XX errors and their own errors. I've done something like this in the past. There was a (horrible) reason; old versions of Android had terrible built-in HTTP stuff and tended to break on any 'unusual' HTTP responses (for instance, 2…

Ugh, i'd put a gateway in front of it that transformed the status codes to a 200-response.

Instead of building your api according to the default Android client ( ps. Lookup BFF microservices)

Re: API Practices If You Hate Your Customers

#132

I thought the chosen example for idempotent requests was a bit funny as I don't think POST is necessarily idempotent and depending on your specific use case making it so may or may not be easy.

POST is explicitly not idempotent.

...and the given example of something that should be idempotent is posting to create a new VM instance. Which you certainly may do. It's just a funny choice of example since that's the one example where the behavior he describes is potentially expected.

Re: API Practices If You Hate Your Customers

#133

Earlier quoted context omitted.

POST is explicitly not idempotent.

POST isn't required to be idempotent, but to be clear it's not improper to make an API with idempotent POST endpoints.

Which is exactly why it's a fairly unusual choice for an example.

Re: API Practices If You Hate Your Customers

#134

I thought the chosen example for idempotent requests was a bit funny as I don't think POST is necessarily idempotent and depending on your specific use case making it so may or may not be easy.

It requires passing in an id of some sort. Client generated ids are cool for a lot of things; I wouldn't use them for everything.

Completely agree with you.

Re: API Practices If You Hate Your Customers

#135

Earlier quoted context omitted.

> When pointed out, the support answer was "we chose to give meaningful error messages instead of HTTP codes, that's why we respond with 200 in case there's an error in the request". Not the answer I was expecting. I don't see the problem here. As a developer I'd much rather receive a standard json packet with information helping me figure out what went wrong. I really don't understand your complaint here, I've desig…

A huge and borderline criminal conflation with HTTP in general and REST-y APIs. The big fat elephant in all this is simple; None of our fucking opinions matter one god damn bit to the end client. Being originally designed to you know, consume hypertext over the hypertext transfer protocol, clients can and will do whatever the fuck they want with the status codes.

Well, speaking as a client developer, the API is far, far easier for me to understand and write logic against if its authors agree to send back HTTP statuses with their standardized meanings instead of making up their own scheme.

Re: API Practices If You Hate Your Customers

#136

Earlier quoted context omitted.

> I had to work with an API where the company decided everything should return http code 200 (well, at least all 4XX errors), and give the error code in the JSON response, mixing existing 4XX errors and their own errors. I've done something like this in the past. There was a (horrible) reason; old versions of Android had terrible built-in HTTP stuff and tended to break on any 'unusual' HTTP responses (for instance, 2…

Ugh, i'd put a gateway in front of it that transformed the status codes to a 200-response. Instead of building your api according to the default Android client ( ps. Lookup BFF microservices)

It was a while ago, and we were very cost sensitive.

FWIW, I think the last Android phones with these client issues have probably died by now (it got mostly sorted out in 4.3 or so IIRC); this isn't a current concern.

Re: API Practices If You Hate Your Customers

#137

Earlier quoted context omitted.

You need to know that “results” is an array so you need the schema. In JSON an array is an array without doubt.

If you don't know that "results" is an array... how do you handle the uncontroversial case of getting back an array of two results?

I know that but the PHP deserializer doesn’t know and gives me back an object instead of an array of one. If it’s two it detects an array.

Re: API Practices If You Hate Your Customers

#138
post #44

Earlier quoted context omitted.

There's often a semantic difference between null and empty. Like, if I'm checking the result of a batch processing job, I want to know if the job finished & resulted in an empty set, or there is simply no result yet. It's "the thing you're looking for doesn't exist" vs. "the thing you're looking for exists, but is empty."

That's fair to say I guess - but it should be accompanied by some other property to indicate a condition like that. The API I'm thinking of though was effectively a wrapper around a database query which retrieved items. That's what gets me about that decision you see. When you get nothing from a database, you get an empty set. The runtime was some version of .NET Framework, which by default would write an empty set a…

I've seen this happen due to system evolution. At first some entity may have a parent record or not. So when you ask for the parent, you either get it, or null.

But then the system evolves to not be many-to-one, but many-to-many. To avoid breaking old clients, they make it so the only difference is when they return multiple related records, in which case they're given in an array.

Thus you now have: null for empty, the record it self if there is only one related, and an array of records if there are more than one related.

Re: API Practices If You Hate Your Customers

#139
Use of multiple different sets of allowed characters in identifiers for entities in your API is also a good way to show you customers that you hate them..

Extra bonus points for intermittently using case-insensitive but case-preserving identifiers.

Microsoft Azure storage APIs is a prime example of this with 4-5 different sets of identifier restrictions dependening on what you're naming. (Including one that allows any valid C# identifier, for which the documentation conveniently refers to the ECMA specification of C#).

Also enabling some special characters like # when creating entities, while knowing that # will be interpreted differently when fetching entities. Such that entities with # in the key cannot be fetched or deleted, but only created.

Extra extra, bonus points for retaining # support in the interest of backwards compatibility :)

Re: API Practices If You Hate Your Customers

#140
post #44

Earlier quoted context omitted.

There's often a semantic difference between null and empty. Like, if I'm checking the result of a batch processing job, I want to know if the job finished & resulted in an empty set, or there is simply no result yet. It's "the thing you're looking for doesn't exist" vs. "the thing you're looking for exists, but is empty."

That's fair to say I guess - but it should be accompanied by some other property to indicate a condition like that. The API I'm thinking of though was effectively a wrapper around a database query which retrieved items. That's what gets me about that decision you see. When you get nothing from a database, you get an empty set. The runtime was some version of .NET Framework, which by default would write an empty set a…

My example was pretty contrived– I would also expect some sort of flag representing the state of the job in that case.

My point was just that the absence of a value is distinct from an empty value. And that intentionally modeling those 2 cases separately can remove a lot of ambiguity.

Post reply on HN