Live data from Hacker News

How to (and how not to) design REST APIs

github.com

101–110 of 153 posts

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

#101
post #98

I’d just like to interject for a moment. What you’re referring to as REST, is in fact, JSON/RPC, or as I’ve recently taken to calling it, REST-less. JSON is not a hypermedia unto itself, but rather a plain data format made useful by out of band information as defined by swagger documentation or similar. Many computer users work with a canonical version of REST every day, without realizing it. Through a peculiar turn…

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

sorry, an hypermedia

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

#102
Since you invited comments:

Rules #1, #2, #3: I don't feel these are rules as much as aesthetic opinions. The only thing that matters is for URLs to be unique, and no client should rely on parsing slashes on URLs to derive how data is structured.

Rules #4, #5: Very specific to how data is serialised, I wouldn't take it as a rule, although the future-proofing argument is good.

Rules #6, #7: I feel these are sensible rules in general, not even specific to REST.

Rule #8: 404 or 200 is context specific, but what I would say is that if you can represent the absence in the resource do it, otherwise use 404.

Eg: if the student 99 doesn't exist, GET /students/99 returns 404; but if you want to represent there are no students, GET /students/ can return 200 OK with a [] body – since that _is_ the representation of such information. Many APIs fail here, returning 404 on a resource like GET /students/ that is expected to always exist.

And, definitely don't use 401 GONE in a way that's not in RFC.

Rule #9: I believe it's a good idea to minimize the variation in resource representation in general, this benefits both the client and the server by allowing the reuse of cached data.

Rule #11: Agree. I would go further and even ignore mechanisms like 24 hours temporary idempotency keys - just straight allow clients to PUT a resource with whatever ID, following advice from Rule #6, and be done with it.

All in all, this shows "REST" really means different things to different people at this point, we probably need better definitions for the good practices at the different levels (data structures, HTTP compliance, serialisation).

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

#103
I work on enterprise observability, professionally. I think conflating service names (such as /product) and service parameters (such as /product/{product_id}) in the same syntax is a big mistake.

The reason is you want tools to be able to tell a difference and discern how to categorize by service (for reporting). Also, there are privacy implications for monitoring tools, since query parameters might contain sensitive data.

There already are query parameters in the URL, that is better. I wish people never went with the idea of putting parameters in the path.

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

#104

This falls down as soon as it makes a fundamental misunderstanding of what makes a REST api into a REST api. It gives this as a ‘bad’ example: GET /v3/application/shops/{shop_id}/listings/{listing_id}/properties With the justification that “The {listing_id} is globally unique; there's no reason for {shop_id} to be part of the URL. “ No the point of the API is that /v3/application/shops/{shop_id}/listings/{listing_id}…

You apparently have not actually used Etsy's API. No, the shop id is not in fact part of the globally unique identifier of an Etsy listing, and the properties are not dependent on the shop. Etsy listings have a 1:N relationship with Etsy shops. The API was a mistake, which they are slowly correcting - they've already changed: GET /v3/application/shops/{shop_id}/listings/{listing_id} to: GET /v3/application/listings/{…

> Managing permissions using the hierarchy of a URL is silly at best, dangerous at worst.

Or perhaps what you call silly is just you being unaware of what you don't know. There are valid cases to handle permissions using the structure of URLs. As well, the danger you allude to comes from handling it naively. Even the hypothetical attack you suggest might be among the first thing any non-tech savvy person might think of trying.

The scenario you're describing above is simply one of dealing with redundant information in a situation where inferring the whole from the part is not detrimental (for the platform). A case can certainly be made that with that simplification, some optimization opportunities are also lost. Perhaps Etsy doesn't need them. Others might.

> The client cannot be trusted to provide the correct shop id.

The client cannot be trusted period. If I provide a signed cookie that contains a list of authorized shops and they return something else, good thing that cookie is signed. Also good thing the cookie contains the shops, no need to touch the disk if the URL doesn't match the list.

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

#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 update Arrays in an idempotent way. When you use a Map object, you can update individual items in the object by their keys. That is why I think you should avoid Arrays in API data structures as much as possible.

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

#107
post #40

Earlier quoted context omitted.

You use plurals anyway to fetch collections: GET /students So you can't escape the problem unless you want `GET /child` to fetch multiple children. Also, you should avoid verbs in URLs (IMHO, of course). You're adding to the students collection, so post to students: # BAD POST /student/create # GOOD POST /students

"POST /students" is a create action, but verbs are fine for individual entities, for example "POST /students/ID/enroll".

I use Nouns exclusively in APIs, not verbs. URLs define resources. Resources are (99% of the time) Nouns.

So POST /students/{id}/enrollment

Or POST /students is the act of enrolling a student, so the returned Location might be /students/{id}/enrollment to reflect the current state of that resource.

The other details of the student might be at URLs like /students/{id}/details, /students/{id}/results, /students/{id}/courses etc etc

If I end up having part of a "sub-resource" in the "main" resource, then I try to always have an href, otherwise you have to put all of the information.

So GET /students/{id} might return a JSON object with an embedded "enrollment" object, but that embedded object would have an href to the full enrollment resource.

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

#108

Earlier quoted context omitted.

You use plurals anyway to fetch collections: GET /students So you can't escape the problem unless you want `GET /child` to fetch multiple children. Also, you should avoid verbs in URLs (IMHO, of course). You're adding to the students collection, so post to students: # BAD POST /student/create # GOOD POST /students

An API is not an essay, in OOP you write Array and not Array and yet you understand the type is about an array of students. Getting hung up on grammar in an API is probably the dumbest problem to have. If you think `GET /student` is confusing, or more importantly, structurally restrictive as an API, you can think about it as `GET /student/filter` where the "filter" may be a specific student id, or a range of ids, or…

If I use turning a lamp on and off, I'd do GET /lamp and in the response there should be an href with a rel of "on" that I can follow (in JSON land).

In HTML, I might have a FORM that does a POST of the lamp's switch to /lamp/switch.

Because the switch is the resource that you're trying to manipulate when turning a lamp on/off, not the lamp itself.

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

#109
post #63

Earlier quoted context omitted.

An API is not an essay, in OOP you write Array and not Array and yet you understand the type is about an array of students. Getting hung up on grammar in an API is probably the dumbest problem to have. If you think `GET /student` is confusing, or more importantly, structurally restrictive as an API, you can think about it as `GET /student/filter` where the "filter" may be a specific student id, or a range of ids, or…

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

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

#110

Rule #1 is terrible advice. Avoid plural nouns in English API endpoints because English is full of irregular plurals. For example: goose -> geese child -> children index -> indices vertex -> vertexes analysis -> analyses This makes English plurals unpredictable especially for for non-native speakers and hurts API consistency and discoverability. Also consider that for a CRUD interface you may need the singular form a…

> for a CRUD interface you may need the singular form anyway (POST api/student/create) Why? What's wrong with api/students/create? > Avoid plural nouns in English API endpoints because English is full of irregular plurals. I don't buy this. I mean, yes, it's true, but how often do people really need to write these endpoints after initially writing the client code?

Verbs in a URL are an API "smell" for me.

URLs refer to a resource that you can manipulate. What resource is /students/create referring to?

Post reply on HN