Live data from Hacker News

How to Design Better APIs

r.bluethl.net

111–120 of 238 posts

Re: How to Design Better APIs

#111

Do you guys use plural or singular terms in your API endpoints or both? /books /books/:id /book /book/:id It gets harder to keep consistent when there are a lot of nouns that have the same singular/plural form like "clothing"

I always prefer singular just because it's easier to spell if you know the type.

It's stupid to have /geese return a Goose.

If the APIs were in Esperanto it would be different.

Re: How to Design Better APIs

#112

Earlier quoted context omitted.

> Pagination is the devil. The state of the server can change while the user is paginating, leading to fragile clients. Don't paginate your API. The problem is not pagination, and the solution is not to avoid pagination. The problem is offset-based pagination, and the solution is to use cursor-based pagination. > If you think you have a need to paginate, have one API call return a list of IDs, and have a separate API…

Cursor-based pagination doesn't solve your state issue, it forces the server to create a copy of state for the cursor request. This is complex to implement correctly - for example, if the user does not actually paginate through all the entries, when do you dump the unused cursor? If the user issues the same request over and over, do you return a cached cursor or re-copy the state into a new cursor? If you re-copy the…

You appear to be referring to a database cursor.

It is quite simple to implement pagination in the application layer using a unique record identifier (primary key or ULID or ...) as an anchor for the navigation. From that unique ID, we can then fetch the previous `n` or the next `n` records, depending on the direction of the navigation.

This way, the server remains stateless, since the anchor (possibly sent as an encoded / obfuscated token, which can include some other parameters such as page size) is supplied by the client with each pagination request.

Unless I am missing something in your argument.

Re: How to Design Better APIs

#113
post #67

a) Use standardized error codes, not standardized error messages. Clients are responsible for internationalization, which includes presenting error messages in the user's language. If you document a set of error codes as an enum, the client can present a user-friendly error message in the user's language based on the error code. If there are dynamic parts of the error message, i.e. "404: There is no user with ID 1234…

Pagination is harder than it seems to get right.

I think pagination is only predictable under these conditions:

1) The offset used for the next fetch must be based on a pointer to a unique key. We can't rely on the number of rows previously seen.

With this rule, deletes which occur to rows in previous pages will not cause unpredictable contractions.

2) The paged result set must be sorted based on a monotonically increasing field, like created_at, plus enough other fields to create a unique key. You could lean on the PK for this, i.e.: ORDER BY (created_at, id) ASC.

With this rule, new inserts which occur during page enumeration will only affect unseen pages (and we'll see them eventually)

The API call looks roughly like this:

  /orders/?region=US&offset=(2022-03-12T07:05:58Z&ord_1234)&limit=100

The DB query looks roughly like this:

  SELECT *
  FROM orders
  WHERE (created_at, id) > (:offset_created_at, :offset_id)
  OR (
    :offset_created_at IS NULL 
    AND :offset_id IS NULL
  )
  ORDER BY (created_at, id) ASC
  LIMIT :page_size
EDIT: formatting

Re: How to Design Better APIs

#115
post #44

Earlier quoted context omitted.

I don't think I've ever come across any third party actually implementing HATEOAS ( https://en.wikipedia.org/wiki/HATEOAS )

Chrome, Safari, Firefox, Edge, and Opera are all third-party clients for the HATEOAS-based API known as the World-Wide Web.

What?

Re: How to Design Better APIs

#116
post #2

The error messages could be better yet. The example uses a different code per issue, for instance: "user/email_required". Most integrators will build their UI to highlight the input fields that contain an error. Making them parse the `code` field (or special-case each possible code) is pretty toilsome. // from blog post { "code": "user/email_required", "message": "The parameter [email] is required." } Make it parseab…

Localization has entered the chat.

You need codes because the field isn't going to be 'email' for much longer than it takes for your management to realize that people outside of the US also have wallets.

Re: How to Design Better APIs

#117

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…

Have you seen: https://github.com/twitchtv/twirp

Re: How to Design Better APIs

#118
post #2

The error messages could be better yet. The example uses a different code per issue, for instance: "user/email_required". Most integrators will build their UI to highlight the input fields that contain an error. Making them parse the `code` field (or special-case each possible code) is pretty toilsome. // from blog post { "code": "user/email_required", "message": "The parameter [email] is required." } Make it parseab…

Localization has entered the chat. You need codes because the field isn't going to be 'email' for much longer than it takes for your management to realize that people outside of the US also have wallets.

Field ids are not (necessarily, especially when doing localization) something shown in the UI. The point made by the original commenter is that a field in the error should refer directly to which field has an issue. It does, via an id that happens to be "email". It's still up to the clients to decide how to represent that to the user, but they're given a distinct field rather than needing to infer which field an error code refers to.

(While the comment I replied to can be read differently, I assume we all know that changing actual field names (in APIs) depending on localization is nuts)

Re: How to Design Better APIs

#119
post #46

Earlier quoted context omitted.

It might be to formal for your use-case, but there is a standard defined for error responses in RFC 7807: https://datatracker.ietf.org/doc/html/rfc7807

Wow, I had never seen an API with errors at this level of detail… I feel lucky when they at least use sane status codes instead of always giving back 200 and a maybe-json-maybe-plaintext-maybe-empty body… I’d love to hear from anyone who has encountered APIs in the wild that actually implement this standard!

I used to work at Akamai and Problem Details is used in most of their APIs. It might have something to do with the fact that one of the RFC authors (Mark Nottingham / @mnot on HN) worked there for a while.
Post reply on HN