I'm working on an API (along with an SPA) for a private project and I can't decide between two route naming conventions.
Suppose I have three tables in my database : Users
, Products
and Orders
. If I want users to be able to order products, which one of the following conventions should I follow?
POST /orders
with body { "product": 1 }
POST /products/{id}/order
Note : In both case the user
would be inferred based on the access token provided.
To me, the main difference between the two solutions above resides in the type of interface to expose to the front-end developer : do I expose routes to resources (solution 1) or to actions to be performed (solution 2)?
Are there actual (dis)avantages to use one method over the other or is it just a matter of personal taste?
Correct me if I'm wrong, but from my understanding solution 1 is REST ("create this resource") while solution 2 isn't ("perform this action").
Also, with solution 1 each route would directly map to a table in my database and some people say it's a bad idea cause external developers can then infer the database's schema based on the API routes but honestly I don't see how it's a problem.
Based on my researches and on GitHub and Instagram APIs' endpoints, for a user to order a product what makes the most sense is to expose POST /users/123/orders {"product": 456}
instead of POST /orders {"product": 456, "user": 123}
. The idea here is to think about the context of a resource if there's one.
Notice that we don't need to use the 'update' verb phrase in the URL because we can rely on the HTTP verb to inform that operation. Just to clarify, the following resource URL is redundant:
PUT http://api.example.com/customers/12345/update
With both PUT and 'update' in the request, we're offering to confuse our service consumers! Is 'update' the resource?
4. Use sub-resources for relations
If a resource is related to another resource use subresources.
GET /cars/711/drivers/ Returns a list of drivers for car 711 GET /cars/711/drivers/4 Returns driver #4 for car 711
GitHub and Instagram APIs seem to work this way too, that is to use the context of a resource when it's relevant.
For example if you want to get a list of a user's organizations using GitHub's API you'll use GET /users/flawyte/orgs
and not GET /orgs {"username": "flawyte"}
.
Same with Instagram's API if you want to like a media : POST /media/{media_id}/likes
.