Live data from Hacker News

How to (and how not to) design REST APIs

github.com

51–60 of 153 posts

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

#52
post #8

Doing REST microservices is incredibly slow because of the amount of work it is to agree on what a "clean" and "consistent" api looks like for each service. It's just such an endless well of trying to establish best practices without refactoring constantly. It's worth it for your public API, but it's such a huge time sink for internal APIs.

I would be interested in what you are using internally that is allowing you to move quicker.

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

#53

Half of the points are complete bs. URLs don’t matter in REST. What matters are link relations.

I would go even further and say that REST is BS Most people understand REST as a format for URLs and a particular semantics for HTTP methods. While it can be perfectly ok to design an api like person?id=123. This is the way that Postgrest does it, which works, and makes certain things like entities with composite primary keys way easier.

Other, like OP, think REST isn't going far enough in that HATEOAS is what "really" makes something restfull. This doesn't really work in practice as if changing the schema of some JSON response can magically change the behaviour of an application. I you want to lift all the logic to the server, I guess you can use htmx, but then you are not building an api anymore but a remote rendering engine.

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

#54
post #43

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…

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.

Of course it's not always like that, some APIs will put both the error and data in a wrapper object and one field or the other will always be null:

    {
        "error": null,
        "result": {"id":"THG123", "name":"thingie"}
    }
This is less annoying but it's still tedious. We could eliminate the wrapper if we only had an out-of-band signal to indicate whether the client should expect a success response or an error response... like maybe an HTTP status code? I mean, it's right there, why not use it?

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

#55
post #46
post #38

“RESTful” API design is mostly bike-shedding. There’s no standard. Every REST API looks different. Clients have to refer to documentation anyway, so consistent URL patterns achieve nothing. People waste large amounts of time over totally inconsequential minutiae like whether to use singular or plural words in URLs. Separating idempotent calls from non-idempotent calls is useful, but REST overcomplicates this. All tha…

Agree. But I pick REST (or “json over http”) any day of the week instead of graphql, soap, grpc, etc.

Graphql just for the sake of graphql is a disaster for backend engineers.

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

#56
post #47

I’d add: * If you’re going to forbid people changing a parameter with a PUT or PATCH request, then the schema for these shouldn’t list them as parameters. This seems to creep in to APIs constantly as people are lazy and will use the same serializer method as for POST with an additional check somewhere in the code that changes the response. Just don’t do it! * Don’t change the response format based on query parameters…

I very much agree with your first and third point, from experience. As for the second one — if consuming dynamic data structures is hard in typed languages, maybe they are not the right tool for that particular job? What I have seen is endpoints trying to corral their responses into one-size-fits-all schemas in the situation you're describing, with predictable outcomes. Lots of overhead in most situations, tricky doc…

As for the second point, that's what Accept header is for. And I personally never had much trouble in Go with deserializing all those "weird response types" but it may depend on one's coding style.

> I have to say that at least for generic APIs with many differing clients, the idiosyncrasies of typed-language clients would not rank too highly on my list of design considerations

Hey, would you like to consume an exchange format that has meaningful distinction between strings and atoms? Those come from the dynamically-typed languages area!

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

#57
post #29

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

Does “GET /students” return all the students in the system? Probably not. So in fact you’re fetching some subset of students anyway, and the size of the returned set might be one or zero depending on your query. Given that, “GET /student” seems just as meaningful because neither the singular nor the plural can fix the ambiguity about what you’re actually getting.

I expect singular to return one, and plural to return a set, which could range from 0...n.

Likewise, I wouldn't expect a singular to return a single object wrapped in an array, but I would always expect "/plural" (with no further qualifier in the url) to return an array, regardless of 0, 1 or more results.

Why would returning a full set be a condition of whether or not plural is ambiguous?

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

#58

Found a contradiction that I don't understand. From rule 1: # GOOD GET /products # get all the products GET /products/{product_id} # get one product # BAD GET /product/{product_id} But then in Rule 2: GET /shop/{shop_id}/listings # normal, expected Shouldn't that be "/shops/{shop_id}/listings"? Or is it plural only if you can actually GET the path (i.e. there's no GET for just "/shop") and otherwise it should be sing…

Plural or singular seems far too marginal to be good or bad. I use singular.

I use singular too, but I always wonder to those sticking with plural - what's the convention for words which plural and singular are the same.

ie - like 'staff' or 'species' or 'aircraft'.

Then I can add suffix to those singular ie - 'staffList', 'speciesList' etc

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

#59

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…

> Some good points - particularly about not returning arrays.

I don't get that one; why is an object with an array property more evolution friendly than an array of objects?

Post reply on HN