ThomasNichols89
ThomasNichols89

Reputation: 129

How best to structure a RESTful API Endpoint

I'm working through a transition of my app from a tightly coupled PHP implementation to a RESTful implementation. (current app at http://coinvault.tanichols.com)

The app maintains a collection of coins (state quarters, presidential dollars, etc) and users. A user can also 'collect' a coin, represented as a many-many relationship between the user and coin tables.

I've created the following table of verb and endpoint combinations:

GET    /coins               - Get all coins 
POST   /coins               - Create a new coin
GET    /coins/CID           - Get a coin
PUT    /coins/CID           - Update a coin 
DELETE /coins/CID           - Delete a coin

GET    /users               - Get all users
POST   /users               - Create a new user
GET    /users/UID           - Get a user
PUT    /users/UID           - Update a user
DELETE /users/UID           - Delete a user

What I'm having trouble with is the proper/accepted way of exposing information from the many-many table. For example, I could use the following set of routes:

GET    /users/UID/coins     - Get coins for a user
POST   /users/UID/coins     - Create a coin for a user
GET    /users/UID/coins/CID - Get a specific coin for a user
PUT    /users/UID/coins/CID - Update a specific coin for a user
DELETE /users/UID/coins/CID - Delete a specific coin for a user

or I could invert this to:

GET    /coins/CID/users/UID - Get a specific coin for a user
PUT    /coins/CID/users/UID - Update a specific coin for a user
DELETE /coins/CID/users/UID - Delete a specific coin for a user

Q1: Is one of these preferred over the other? Is there a standard or accepted way of planning these types of routes?

I could also expose this functionality with the following route and filter:

GET    /coins?user_id=1     - Get all coins belonging to a user

Q2: Is this a better approach, or worse? Does this add unnecessary 'weight' to the /coins route?

Finally, there's the situation where I want to provide access to some aggregations, such as a count of how many times a particular coin has been collected, for reporting and analytics purposes. For this one, I'm at a complete loss on where to begin, or how to approach the problem.

Q3: How does one expose such aggregations through a RESTful API? What is a meaningful route for this?

Upvotes: 3

Views: 2026

Answers (1)

Arnaud Lauret
Arnaud Lauret

Reputation: 5291

Q1:

The way you represent collections and items is valid in absolute but your first proposal is valid in your context:

GET    /users/UID/coins     - Get coins for a user
POST   /users/UID/coins     - Create a coin for a user
GET    /users/UID/coins/CID - Get a specific coin for a user
PUT    /users/UID/coins/CID - Update a specific coin for a user
DELETE /users/UID/coins/CID - Delete a specific coin for a user

If a thing belongs to someone, you represent it with /someones/SID/things/TID.

Q2:

This proposal:

GET    /coins?user_id=1     - Get all coins belonging to a user

is definitely not a good idea, it goes against REST best practices.

Q3:

It's not a matter of aggregation, these data are bound to a coin, therefore you could simply return them within the data of GET /coins/CID. Multiplying endpoints is definitely not a good idea, especially if these data will be always needed.

Upvotes: 3

Related Questions