ByteByteGoHq / system-design-101

Explain complex systems using visuals and simple terms. Help you prepare for system design interviews.
https://blog.bytebytego.com/
Other
64.03k stars 6.75k forks source link

REST design comments #20

Open icebob opened 1 year ago

icebob commented 1 year ago

Hi,

I have some comments for the section on effective REST API design:

1. Use the same casing method You use camel-case in most variable names except the sort_by. It would be better as sortBy to follow the conventions. image

2. Skip the action from URL path The "Idempotency" example shows a good path POSTS /carts without any action name. But the cart example URL contains the action name. It is unnecessary because the POST method defines the action. image So I recommend changing it to POST /carts/123/items { itemId: "321" }

By the way, nice collection, good job!

macieyng commented 1 year ago

Yeah! I agree with you on both. I was reading this REST table and wondered if some asked about it.

So I want to get a little bit deeper. People say that http verbs (get, post, put, delete, etc) is all you need to perform an action and that paths should only contain resources (so nouns). Example here shows that path includes a verb :add. While I think that this specific point can be a little confusing, my question isn't about convention, but have anybody seen using this pattern successfully? Like what's the reasoning? And if so why not POST /carts/123/items/add? Going even further - how does it fit in hateoas picture?

I just started reading Roy Fielding dissertation on REST and I'm hoping to get some answers about REST.

icebob commented 1 year ago

The add is the same as create, but for creating a new entity, we don't write create in the path, just using POST method. This is why I use POST /carts/123/items only.

However, I'm using the verb in the path if it's not a CRUD action and mutating a certain item, e.g increaseQuantity: POST /carts/123/items/321/increaseQuantity

macieyng commented 1 year ago

But then why not

PUT /carts/123/items/321
{"quantity": <new quantity>}

or

PUT /carts/123/items/321
{"increaseBy": 1}
icebob commented 1 year ago

In CRUD methods, the PUT is used to update an existing record (entirely) and the PATCH is used to update an existing record (partly). POST is the common mutation method.

Btw, currently, there is nothing any strong definition of the HTTP methods.

macie commented 1 year ago

@macieyng REST is about having easy to remember interface. There are limited number of possible actions (HTTP method) which can be applied on arbitrary resource ID (URI) and they may respond with one of known number of error states (HTTP response status code). So instead of

PUT /carts/123/items/321
{"quantity": <new quantity>}

you can do:

PUT /carts/123/items/321/quantity
<new_quantity>

This resource path don't need to be mapped 1:1 to database object, object in your language or filesystem path.

Path with verb is sign, that author has RPC mindset. API which mixes RPC with REST will be difficult to understand and error-prone ("is PUT /item/2/increase idempotent?", "which error message strings can we safely ignore?").

HATEOAS is about API self-discovering - you should be able to learn possible actions from result only. JSON wasn't designed with that in mind, so now we spend time on Swagger and API exploration tools. See: How Did REST Come To Mean The Opposite of REST?.