Live data from Hacker News

How to (and how not to) design REST APIs

github.com

141–150 of 153 posts

Re: How to (and how not to) design REST APIs

#141
post #98

Earlier quoted context omitted.

I'm on your side, but every time you say "a hypermedia" it kills me.

I'm not a native English speaker so, honest question: isn't h a consonant with its own distinct sound, so a instead of an?

> isn't h a consonant with its own distinct sound

Usually, including in “hypermedia”, but “hypermedia” is either an adjective or a mass noun, not a countable noun of which you can have a single instance.

“a hypermedia... ” looks like you are using it as an adjective to modify a countable noun, and when there is no noun looks like you forgot the noun; “JSON is not a hypermedia unto itself...” should probably be something “JSON isn’t hypermedia unto itself... ” (I’d actually prefer “JSON, on its own, isn’t hypermedia”, but that gets behind the issue with the use of the indefinite article.

Re: How to (and how not to) design REST APIs

#142

Earlier quoted context omitted.

I'm not a native English speaker so, honest question: isn't h a consonant with its own distinct sound, so a instead of an?

> isn't h a consonant with its own distinct sound Usually, including in “hypermedia”, but “hypermedia” is either an adjective or a mass noun, not a countable noun of which you can have a single instance. “a hypermedia... ” looks like you are using it as an adjective to modify a countable noun, and when there is no noun looks like you forgot the noun; “JSON is not a hypermedia unto itself...” should probably be someth…

We take english grammar from the corrupt! The rich! The oppressors of generations who have kept you down with myths of uncountable nouns... and we give it back to you... the people.

Re: How to (and how not to) design REST APIs

#144
post #93

Some good points - particularly about not returning arrays (I've made that mistake!) But I feel 410 instead of 404 is pretty controversial: > There are many layers of software that can return 404 to a request Anything in your stack can return any HTTP error code - I don't see why 404 is special. > When calling (say) GET /things/{thing_id} for a thing that doesn't exist, the response should indicate that 1) the server…

There are two reasons behind 404 being a bad response code to use for empty results. - Did I get a 404 on this endpoint because the endpoint doesn't exist? Or did I get that because the object I was looking for doesn't exist? Great, I need to dig into the response body to find out, indicate that I can either get a 200 or a 404 with this endpoint, and deal with the odd case where the API returns HTML regardless of the…

If anything that's not 1/2/3xx is a problem then 410 won't be a solution. And I doubt that your http library having issues to handle 4xx can handle 1xx correctly.

Re: How to (and how not to) design REST APIs

#145
post #109
post #63

Earlier quoted context omitted.

> Fielding's own examples from his blog, how'd you turn a lamp on and off via REST? Would you be like `POST /lamp`? No. It's unclear WTF is happening. No, of course you'd be like `PATCH {"light": "off"} /lamp`! Kidding of course but it's true that REST purity does not make for intuitive APIs in complex real-world problem domains.

In HTML, you could have a FORM with the URL of /lamp/switch that you PUT.

PUT is not a valid method from an HTML form. Only GET or POST are permitted.

Re: How to (and how not to) design REST APIs

#146
post #145
post #109

Earlier quoted context omitted.

In HTML, you could have a FORM with the URL of /lamp/switch that you PUT.

PUT is not a valid method from an HTML form. Only GET or POST are permitted.

This kind of reveals a little secret of many of the REST gurus. They have no clue what they're talking about.

Re: How to (and how not to) design REST APIs

#147
post #105

The "v3/application/shops/{shop_id}/listings/{listing_id}/properties" structure is typically important for database partitioning when using e.g. DynamoDB. You have to include both the partition key and the sort key in the URL to access the database item. Otherwise the database doesn't scale out as intended. I also disagree with the advice to always use Arrays instead of Map objects. It is very difficult to partially…

Why would you update your input. It's just input, you can locally have maps. Say for example when you read SQL results, it's a list of results, not a map of results. Then you make a map of whatever key you need locally. Or even several of them.

    let myCustomIndex = listOfResults.reduce((i, r) => {
        i[r.pk] = r;
        return i;
    }, {});
In general we call serialization "serialization" because we put things in serial order and send that sequence over the wire. You can't send maps over the wire. A map is a structure in memory optimized for direct access and modification. While JSON maps (objects) are just sequences of keys and vals, encoded as text, not an actual hashmap or a b-tree, as we surely understand.

So you may as well save the redundancy and send a list of results, then format and index it however you please locally.

The fact JSON has maps (objects) at all is a lot less useful than people realize. It's mostly useful for the purpose of denoting "that's a key" and "that's a value". But actually all the work is done after the JSON is being read. You can just as easily send a "map" like this:

    ["key1", "val1", "key2", "val2", ...]

Re: How to (and how not to) design REST APIs

#148
post #105

The "v3/application/shops/{shop_id}/listings/{listing_id}/properties" structure is typically important for database partitioning when using e.g. DynamoDB. You have to include both the partition key and the sort key in the URL to access the database item. Otherwise the database doesn't scale out as intended. I also disagree with the advice to always use Arrays instead of Map objects. It is very difficult to partially…

Why would you update your input. It's just input, you can locally have maps. Say for example when you read SQL results, it's a list of results, not a map of results. Then you make a map of whatever key you need locally. Or even several of them. let myCustomIndex = listOfResults.reduce((i, r) => { i[r.pk] = r; return i; }, {}); In general we call serialization "serialization" because we put things in serial order and…

My point about arrays vs maps is based on the idea that you store the data in e.g. DynamoDB as the same structure as it is represented in the API. If you store an array in an attribute of the database item, you cannot update its contents in an idempotent way. Inserting or appending to the array multiple times (using the relevant DynamoDB functions) causes it to grow more and more each time. Whereas when you use a map object, updating a specific key in the object is an idempotent operation and has no effect when repeated.

I realise this is pretty DynamoDB specific. But there are also other points to be made against arrays, such as being forced to maintain their order in any kind of database, which can be quite bad for performance. When using a key value map object, there is no guarantee of the order of the items and users of the API will reflect this in how they use the API, relying on the object keys instead of array indices or array order.

Re: How to (and how not to) design REST APIs

#149
post #43

Earlier quoted context omitted.

I prefer to consider 404 as protocol error and missing thing as business error. That way 404 signals wrong endpoint and 200 + error message + empty result set signals wrong id. Or even more simple: Anything other than 200 means check infrastructure docs and if you don't like the 200 check the business requirements.

As a client I generally dislike APIs that use 200 for error conditions. The problem is that API implementors often change the structure of the response. GET /thing/THG123 # on success: {"id":"THG123", "name":"thingie"} # on failure: {"error":"no such thing"} Working in typed languages, this requires parsing the response, determining success or failure, then reparsing the response into the appropriate type. Annoying.…

Well, sure, without wrapper object it's annoying. But what's the difference whether you check response.data.error or response.status ?

Re: How to (and how not to) design REST APIs

#150
post #148

Earlier quoted context omitted.

Why would you update your input. It's just input, you can locally have maps. Say for example when you read SQL results, it's a list of results, not a map of results. Then you make a map of whatever key you need locally. Or even several of them. let myCustomIndex = listOfResults.reduce((i, r) => { i[r.pk] = r; return i; }, {}); In general we call serialization "serialization" because we put things in serial order and…

My point about arrays vs maps is based on the idea that you store the data in e.g. DynamoDB as the same structure as it is represented in the API. If you store an array in an attribute of the database item, you cannot update its contents in an idempotent way. Inserting or appending to the array multiple times (using the relevant DynamoDB functions) causes it to grow more and more each time. Whereas when you use a map…

OK but transfer format and working representation shouldn't be the same. That is a bad goal to have. A working representation is sparse, indexed, you can jump to places and change parts. While input (and output) are streams of dense data.

Adding redundancy to input/output so you don't have to make local decisions for your working representation may seem like a simplification, but you're basically chaining yourself from doing what you need to do in order to do work effectively, and burdening input/output with concerns that don't matter on the wire.

We keep seeing this idea come back again and again where "you don't need services" or "you don't need controllers" or "you don't need mapping", so just, you know, grab the database and hose it out over HTTP and into clients as-is. But this always is one of those "immediate gratification" choices that ends up biting you in the ass not long after. It looks great in slides and demos though.

Post reply on HN