Live data from Hacker News

Best practices for REST API design (2020)

stackoverflow.blog

231–240 of 273 posts

Re: Best practices for REST API design (2020)

#232
post #137

Using HTTP methods as verbs is a terrible practice. It works for simple CRUD APIs, but it becomes too limiting once there are more than one way of updating something. It ties the API design too closely to the data model and usually means that the client has to implement more business logic instead of handling that on the server. Good API design should decouple business logic from the HTTP spec.

The basic HTTP methods work in the vast majority of cases. The key is to create the appropriate resources--facades that compose the data model and business logic as needed.

No they don't work for vast majority of cases. They work only for CRUD and imposing resources paradigm on everything looks alien.

Re: Best practices for REST API design (2020)

#233

If you want a pretty decent REST-ish API right out of the box, and you already have a DB, check out PostgREST[0]. More features than you can shake a stick at, and all you have to do is maintain your DB schema. [0]: https://postgrest.org/en/v7.0.0/

I like it and its very fast.

Good luck with scaling and automatic testing tho.

Re: Best practices for REST API design (2020)

#234
Ok the way I do it with Angular and Vue clients (and Go servers) is:

GET /api/vn/singular_name/ = list all

GET /api/vn/singular_name/?field=value = list all filter by query, if it gets more complex base64 encode the query and decode on server

GET /api/vn/singular_name/:id = get by id

POST /api/vn/singular_name/ = create

PUT /api/vn/singular_name/:id = replace

PATCH /api/vn/singular_name/:id = atomic update

DELETE /api/vn/singular_name/:id = duh

If models are related they receive a related_model_id field. This works even for "many to many".

In the case of Vue there's this excellent library called vuex-orm, which handles normalization of incoming data and ways to define relationships or all kinds and also queries with or without related models. It's so good that I'm abandoning Angular because it doesn't have something so sophisticated, despite it having the better component system and structure all together. Not having to subscribe and unsubscribe to data streams and deal with this torture instrument rxjs is a bonus. Because of vuex-orm I'm more productive than I've ever been with Angular.

This is sufficient and there is no need for GraphQL.

Real time updates are simple. Whenever something like INSERT, UPDATE, DELETE happens an event is sent to a notification library which sends those updates out via websocket, a client version of this handles updates of the cache (or if you like vuex state, previously ngrx-data cache). The notification library also handles scoped status updates. Imagine a multi-community site. You're currently in community A and don't care about what happens in community B, the client tells the server "I'm in A" the server notifies the client only about the latest happenings in scope community A. Once you navigate to community B you do a fetch from the server to get the latest version of the truth. But while you're there you're also telling the server "I'm in B, send me real time updates about B".

I'm not a fan of Redis. I like MongoDB and having a single database system for everything. Since I'm not into game development that's good enough. Postgres is nice for querying, I like SQL more than Mongo's way to query but when developing running migrations, database updates, it's a PITA, especially in Go which seems to lack tooling for this and the driver and "o"rm landscape is also a bit barren.

Re: Best practices for REST API design (2020)

#235
post #220

Earlier quoted context omitted.

> Send numbers as string [...] Why? Why not send a number as number (double) and treat it as hostile in the backend? I dislike sending numbers as string because I think the different data types exist for a reason.

Many of the numbers we use day to day are more like strings than actual integers, though. What sense does it make to divide by a zip code, or two add two zip codes together for instance?

This. Just because something contains numbers doesn't mean that it's numeric. Times aren't numbers because 6pm * 7am doesn't yield a meaningful result.

Same thing with serial numbers, VIN numbers, building floor numbers, phone numbers, etc. All of those should always be strings, because performing "math" on them wouldn't yield meaningful results.

Re: Best practices for REST API design (2020)

#236

Earlier quoted context omitted.

Ironically, your comment is a perfect illustration of one of the problems with REST - its tendency to provoke discussion about things that don't actually matter in practice. No user cares whether an error response came back with a 400 or a 409 status, or what those codes even mean. It's madness that as a profession we spend so much of our employers' time and money on trivial things that deliver no value whatsoever. R…

I have been bitten by this really bad idea of reusing HTTP CODE for application problems. The server was 404 itself instead of the application. It is a bad engineering idea to reuse HTTP codes that can be thrown by multiple intermediaries confusing the client code.

Where I work everything internal is a 503. Put a parameter out of range, or supply an ID not in the database? That's a server side exception. It's very frustrating even with a stack trace because I don't work on that code.

Re: Best practices for REST API design (2020)

#237

Earlier quoted context omitted.

Then why add the "in UTC" part? ISO 8601 specifies how to designate the time zone.

ISO 8601 does not contain timezone information, but offset . Timezone info needs to be specified separately, likely as IANA names. It is a common misconception to time zones though, and in a way demonstrates why it’s best practice to always use UTC. When sending/receiving a datetime, no timezone info is available; if timezone is needed, send it separately (and keep the time value in UTC) to save misunderstandings for…

I'm aware of the distinction between ISO 8601's time zone designators (which are simply UTC offsets) and other much more complex notions of time zones such as the IANA tz database (which identifies time zones with an "Area/Location" string and contains information about each zone such as daylight saving time rules and even the historical changes in such rules).

That said, "time zone designator" is the formal name of the UTC offset in ISO 8601, and it's reasonable to refer to it as such whenever the distinction is clear.

Re: Best practices for REST API design (2020)

#238
post #213

Earlier quoted context omitted.

> Send numbers as string [...] Why? Why not send a number as number (double) and treat it as hostile in the backend? I dislike sending numbers as string because I think the different data types exist for a reason.

A bit off-topic but I received an email from a government agency today that pretty printed my ZIP code as "12,345", I'm assuming because they store ZIP as a number. Made me wonder what would happen if I used a full 9 digit ZIP code with a minus sign.

Reminds be of a broadly used industry specific database that packs multi-line addresses in a delimited string with an initial integer which indicates the number of lines. Some addresses were written to the database without the initial integer and were addresses in a city with East/West streets with number names. Addresses like 1425 East 34th St commonly written as 1425 E34 were casted as exponents, so an address with 1.425E37 lines, which was a problem for the ETL-downstream database that attempted to make that many rows for address lines. It caused much confusion and delay for the downstream DBAs.

Re: Best practices for REST API design (2020)

#239
post #159

Most of these best practices forget the hard parts of JSON/REST APIs: - How to handle date and time incl. time zones - JSON has no data type for that - Handling of numbers (JSON only has double, which does not fit most cases) - Defined and parseable error responses (rfc 7807 plus extra fields for details) - Localization - do you send translated texts or just error codes? - How to handle updates? Overwrite every field…

Send ISO date/time in utc. Send numbers as strings. you should be treating this as hostile in your backend anyways, and checking it. Send both an error code, and a string in simple english, or whatever your most common developer language is. If you care about only updating certain fields, track changes and only send those fields to the backend. These arn't really that hard.

>Send ISO date/time in utc.

With offset, ok. As UTC alone, it doesn't work if you need to know the local time when something occurred, like medication administration, especially when the things may occur across time changes like DST.

Re: Best practices for REST API design (2020)

#240

If you want a pretty decent REST-ish API right out of the box, and you already have a DB, check out PostgREST[0]. More features than you can shake a stick at, and all you have to do is maintain your DB schema. [0]: https://postgrest.org/en/v7.0.0/

I like it and its very fast. Good luck with scaling and automatic testing tho.

From-scratch or from-fixture E2E tests to prevent regressions should still be doable though, just gotta bring along your language of choice, and keep a repo around to hold the code/data.
Post reply on HN