0

Consider that I'm using the following RESTful API endpoints:

  • /users/: show all users
  • /users/$user_id/: show specific user
  • /users/$user_id/posts/: show all posts by user
  • /users/$user_id/posts/$post_id/: show specific post by user

Constraint in this data model: a post always has a user.

By "processing nested resources" I mean handling the CRUD operations.

Should I implement the CRUD operations (POST, PUT, PATCH, DELETE) on the /users/$user_id/posts/ endpoint or should I create another endpoint /posts/ and handle the CRUD operations there, while keeping the first endpoint read-only?

Sorry if this question already exists in maybe another form on SO. :-) There's so much "FUD" around RESTful APIs.

Thanks in advance for any tips/clarifications!

Kind regards, K.

Braek
  • 581
  • 5
  • 22

2 Answers2

0

You should implement the operations on the existing /posts/ and /posts/$post_id/ endpoints. There's rarely a good reason to make multiple endpoints that represent the same resources. Why make them figure out that they can only GET on /users/$user_id/posts/$post_id/ but have to go to /posts/$post_id/ to DELETE?

Sometimes, people implement this as

/users/: show all users
/users/$user_id/: show specific user
/users/$user_id/posts/: show all posts by user  -- GET only

/posts/: show all posts                         -- All operations
/posts/$post_id/: show specific post by user    -- All operations

They use /users/$user_id/posts/ as a non-canonical reference to the user's posts. While I can't call it Wrong, it's highly preferable to stick with one endpoint per resource. Filter parameters are not that hard.

Eric Stein
  • 13,209
  • 3
  • 37
  • 52
  • Multiple endpoints for the same resources don't makes sense no. But what about the solution someone mentions in this topic: http://programmers.stackexchange.com/questions/205418/what-is-the-proper-way-of-nesting-resources-in-rest-model While it doesn't make sense to be able to do CRUD operations on multiple endpoints, Javier's point does make sense, no? "POST /partners/:partner_id/tickets - creates a ticket and associates to the partner, returns a 201 with the new URI, of the form /tickets/:id" – Braek Apr 22 '14 at 11:39
  • @kristofvbk If you'd like to do it that way, nobody is stopping you. Javier's approach is not unreasonable. Just make sure you're consistent across your entire API and try to minimize repetition. – Eric Stein Apr 22 '14 at 13:26
0

Following Roy Fielding's clarification regarding REST I would suggest that you shouldn't worry about the design of your URLs:

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC's functional coupling].

A good way to test the RESTfulness of your API is replacing all your carefully constructed URIs with unified IDs and see, whether the client would work with this information. If not than you depend on out of band information and could improve on your RESTfulness. But similar to nth-degree database normalisation you might want to live with a little less 'correctness' in order to make things easier for all participants. How much correctness is required depends how volatile your domain is and whether you expect a smaller or bigger number of API users.

If you want to encode out of band information in the URI I would try to limit the required information as far as possible. Since /users/$user_id/posts/$post_id/ would require the user to know three things (URL design, User ID, Post ID) there seem to be some alternatives that would allow for more ignorance ;-)

  • /posts/$post_id: better, because your user would only need one id and the resource type to construct the URI
  • /$resource_id: best, but requires globally unique ids
xwoker
  • 3,105
  • 1
  • 30
  • 42