Live data from Hacker News

How to Design Better APIs

r.bluethl.net

31–40 of 238 posts

Re: How to Design Better APIs

#31
post #8
post #4

Some nice tips in here. However, tip 15, I strongly disagree with: > 15. Allow expanding resources I would suggest the opposite. A REST API should not return nested resources at all. Instead, and to stay with the example provided on the website, to obtain the "orders", the /users/:id/orders endpoint should be called. It might be tempting to return nested resources, because clients would only have to make a single cal…

Dear PAM69, this is great advice if you want to end up with a slow-to-load, low-performing web application that your customers complain about and hate using. But at least it'll adhere to a specific notion of architectural "purity", right? /s Anytime clients need to make 15 async calls before the UI can be displayed, you're headed up the creek. Generally speaking, this is an anti-pattern. There are exceptions, but the…

Well they said use GraphQL, which is a solid way to avoid REST's clumsiness once and for all.

Re: How to Design Better APIs

#32
post #13

A few things I see rarely discussed that I often do: - Always use a response envelope - HTTP status is not the same as your application status. I always include a "status" field in the response envelope (OP recommends standardizing errors but I think standardize all of it) - Always have an unique error code for every error your API can return (they should also be URL safe ("some-thing-went-wrong"), basically an enum…

Are you able to elaborate on what is a response envelope? Edit: Nevermind, see [0]. It's the simple and intuitive concept of encasing the payload in an consistently structured object which includes metadata, e.g. {"Error": null, Data: ...} [0] https://stackoverflow.com/questions/9989135/when-in-my-rest-... Makes intuitive sense, as it's then easier to develop a nice, generic REST client.

Here's an example straight from code I've rewritten at least 5 times because I'm allergic to saving myself time:

    export enum ErrorCode {
      InvalidEntity = 1,
      NotSupported = 2,
      UnexpectedServerError = 3,
      InvalidRequest = 4,
      Validation = 5,
      // ...
    }

    export enum ResponseStatus {
      Success = "success",
      Error = "error",
    }


    export class ResponseEnvelope {
      public readonly status: ResponseStatus = ResponseStatus.Success;
      public readonly data: T | Pruned | null = null;
      public readonly error?: {
          code: ErrorCode,
          message: string,
          details: object | string,
          status: ResponseStatus,
      };

      constructor(opts?: Partial>) {
        if (opts) {
          if (opts.status) { this.status = opts.status; }
          if (opts.data) { this.data = opts.data; }
          if (opts.error) { this.error = opts.error; }
        }

        if (!this.data) { return; }

        // Prune if the thing is prunable
        this.data = prune(this.data);
      }
}

Hopefully this isn't too hard to grok, it's Typescript.

BTW, If you're cringing at the number scheme for the ErrorCode enum, don't worry I am too. This is why I prefer to use strings rather than numbers, and it basically just ends up being stuff like "invalid-entity", etc.

Re: How to Design Better APIs

#33

Earlier quoted context omitted.

Quoted post unavailable.

I would rather you not assigning hate to the entirety of autistic developers. There are plenty of autistic developers who are fully capable of designing great APIs with awesome usability. Being autistic has nothing to do with how APIs are developed.

No post body was provided.

Re: How to Design Better APIs

#34

Mostly common-sense things, but I can't wait for the community to stop trying to use PUT, PATCH, DELETE and the like. There's a reason that in 2022 web forms only support GET and POST (and implicitly, HEAD).

What is the reason?

I don’t know what OP thinks is the reason, but the actual reason is CORS.

Web Devs (such as me) have asked for e.g. DELETE as an acceptable formmethod (e.g. https://github.com/whatwg/html/issues/3577) however WHATWG always pushes back citing security concerns such as CORS.

I suspect this is not what OP had in mind since it is trivial to send a DELETE request with a simple JavaScript:

    
      Delete
    

Re: How to Design Better APIs

#35
post #8

Earlier quoted context omitted.

Dear PAM69, this is great advice if you want to end up with a slow-to-load, low-performing web application that your customers complain about and hate using. But at least it'll adhere to a specific notion of architectural "purity", right? /s Anytime clients need to make 15 async calls before the UI can be displayed, you're headed up the creek. Generally speaking, this is an anti-pattern. There are exceptions, but the…

Well they said use GraphQL, which is a solid way to avoid REST's clumsiness once and for all.

Sort of, but is it any better if the GraphQL layer still has to make 15 requests in order to serve a single useful response?

Re: How to Design Better APIs

#36

I’m gonna say it: Many rest apis are lazy and developer friendly, not consumer friendly. If you have related resources, let’s say, product and product options as two distinct endpoints: - /api/product - /api/options Then, and I want to be clear here, it is impossible for a client to perform an atomic operation on multiple distinct objects types. Let’s say the client needs to add a product with a single option or fail…

Agree that the tendency exists but don't see the tradeoff between transactional and messy in this example--you should be able to create a new product with options [...] in the same request, perhaps using /options to ascertain what's available before posting to /products, depending on the situation.

Re: How to Design Better APIs

#37
Sometimes, I feel that we ought to have a simple protocol, on top of HTTP, to simply do remote procedure calls and throw out all this HTTP verbs crap. Every request is a http POST, with or without any body and the data transfer is in binary. So that objects can be passed back and forth between client and server.

Sure, there is gRPC, but it requires another API specification (the proto files).

There I said it. HTTP Verbs constrained REST APIS are the worst thing ever. I hate them.

They introduce un-necessary complexity, un-necessary granularity and they almost always stray away from the "REST principles". To hell with "Hypermedia" stuff.

I find it such a joy to program in server rendered pages. No cognitive overhead of thinking in "REST".

But, of course, all this is only where the client and server are developed by the same person / company.

For publishing data and creating API for third party use, we have no serious, better alternative to REST.

Re: How to Design Better APIs

#38

Sometimes, I feel that we ought to have a simple protocol, on top of HTTP, to simply do remote procedure calls and throw out all this HTTP verbs crap. Every request is a http POST, with or without any body and the data transfer is in binary. So that objects can be passed back and forth between client and server. Sure, there is gRPC, but it requires another API specification (the proto files). There I said it. HTTP Ve…

We do, it's called JSON-RPC.

Re: How to Design Better APIs

#39
post #23
post #4

Some nice tips in here. However, tip 15, I strongly disagree with: > 15. Allow expanding resources I would suggest the opposite. A REST API should not return nested resources at all. Instead, and to stay with the example provided on the website, to obtain the "orders", the /users/:id/orders endpoint should be called. It might be tempting to return nested resources, because clients would only have to make a single cal…

That's not a rest-y API. You want GET /orders?user=Id Orders can be searched on many dimensions, not inherent to users

True. But it sort of depends on the kind of relationship "orders" has. E.g. "orders" is a good example to use your suggested GET /orders?user_id=:id and that is probably because an order has a many-to-many relationship, e.g. with users and products (i.e. an order doesn't belong to neither user nor product). However, take something like an "address" which might belong to a user (one-to-many), i.e. the user has ownership of the relationship with an address, in that scenario you probably want to use GET /users/:id/addresses

But then again, when it comes to API's, domain modelling is the hard part and it is therefore the reason why you don't want to return nested results/objects.

Re: How to Design Better APIs

#40

Earlier quoted context omitted.

Huh? There’s full browser support for all of those verbs. What is the argument for not supporting them?

The HTTP request APIs pass through any method name you write. The HTML forms only support GET and POST. Try it.

There is no mention of HTML in these recommendations.

The recommendation is perfectly good for any API using HTTP as the substrate. The wisdom of using HTTP as a protocol substrate is questionable, but having made that decision the verbs it supplies work perfectly well.

Incidentally, the HTML living standard supports three form methods, not two: get, post, and dialog. Which rather reinforces the point that HTML != HTTP.

Post reply on HN