Search code examples
resthttpnaming-conventionshttp-method

Endpoint naming convention for assigning/unassigning data


  1. Imagine e.g. binding table user_tasks(user_id, task_id) with m:n relationship. I want to insert new record. The endpoint should return 204 Status No Content if the record was inserted or if such record already existed. How would you compose such endpoint?

    • GET users/{user_id}/tasks/{task_id}
    • POST users/{user_id}/tasks/{task_id}
    • PUT users/{user_id}/tasks/{task_id}
    • PUT user_tasks + payload: {"user_id": 1, "task_id": 2}
    • Something else?

I would personally go with GET because method is idempotent (if I understand it correctly) and it does not contain payload, but I am not sure.

  1. Now imagine that the table would have one other column: user_tasks(user_id, task_id, position). What is best solution here?
    • GET users/{user_id}/tasks/{task_id}/position/{position}
    • POST user_tasks + payload: {"user_id": 1, "task_id": 2, "position": 3}
    • POST users/{user_id}/tasks/{task_id} + payload: {"position": 3}
    • PUT users/{user_id}/tasks/{task_id} + payload: {"position": 3}
    • Something else?

We have both cases in our project.


Solution

  • Looks like PUT will suit your task better than GET, simply because GET should not modify state on the server.
    From RFC 2616:

    The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI

    Also from there:

    Safe Methods: In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe"

    On the other hand, for PUT:

    The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.

    Seems like it fits nicely, as there is mentioning of possibility that some resource already exists and we probably don't want to create it again. PUT is also considered idempotent.

    Now imagine that the table would have one other column: user_tasks(user_id, task_id, position). What is best solution here?

    Best solution everywhere is to pick the approach that fits you and users of the API best. The only possible downside here could be that one of two mentioned schemes isn't similar to other schemes in the API and some users can find it unexpected.

    Personally I would go with PUT users/{user_id}/tasks/{task_id}/assign?position=3 or with your approach where parameters are passed through payload. I think that the URI should be some identifiable resource, whereas user_tasks doesn't look like one. It looks like an action name, which usually can be seen in the end of URI, for example, look how Twitter did that.