REST URI convention - Singular or plural name of resource while creating it

前端 未结 22 2161
长情又很酷
长情又很酷 2020-12-02 03:35

I\'m new to REST and I\'ve observed that in some RESTful services they use different resource URI for update/get/delete and Create. Such as

  • Create - using
相关标签:
22条回答
  • 2020-12-02 04:03

    I prefer to use both plural (/resources) and singular (/resource/{id}) because I think that it more clearly separates the logic between working on the collection of resources and working on a single resource.

    As an important side-effect of this, it can also help to prevent somebody using the API wrongly. For example, consider the case where a user wrongly tries to get a resource by specifying the Id as a parameter like this:

    GET /resources?Id=123
    

    In this case, where we use the plural version, the server will most likely ignore the Id parameter and return the list of all resources. If the user is not careful, he will think that the call was successful and use the first resource in the list.

    On the other hand, when using the singular form:

    GET /resource?Id=123
    

    the server will most likely return an error because the Id is not specified in the right way, and the user will have to realize that something is wrong.

    0 讨论(0)
  • 2020-12-02 04:06

    For me is better to have a schema that you can map directly to code (easy to automate), mainly because code is what is going to be at both ends.

    GET  /orders          <---> orders 
    POST /orders          <---> orders.push(data)
    GET  /orders/1        <---> orders[1]
    PUT  /orders/1        <---> orders[1] = data
    GET  /orders/1/lines  <---> orders[1].lines
    POST /orders/1/lines  <---> orders[1].lines.push(data) 
    
    0 讨论(0)
  • 2020-12-02 04:07

    Both representations are useful. I had used singular for convenience for quite some time, inflection can be difficult. My experience in developing strictly singular REST APIs, the developers consuming the endpoint lack certainty in what the shape of the result may be. I now prefer to use the term that best describes the shape of the response.

    If all of your resources are top level, then you can get away with singular representations. Avoiding inflection is a big win.

    If you are doing any sort of deep linking to represent queries on relations, then developers writing against your API can be aided by having a stricter convention.

    My convention is that each level of depth in a URI is describing an interaction with the parent resource, and the full URI should implicitly describe what is being retrieved.

    Suppose we have the following model.

    interface User {
        <string>id;
        <Friend[]>friends;
        <Manager>user;
    }
    
    interface Friend {
        <string>id;
        <User>user;
        ...<<friendship specific props>>
    }
    

    If I needed to provide a resource that allows a client to get the manager of a particular friend of a particular user, it might look something like:

    GET /users/{id}/friends/{friendId}/manager

    The following are some more examples:

    • GET /users - list the user resources in the global users collection
    • POST /users - create a new user in the global users collection
    • GET /users/{id} - retrieve a specific user from the global users collection
    • GET /users/{id}/manager - get the manager of a specific user
    • GET /users/{id}/friends - get the list of friends of a user
    • GET /users/{id}/friends/{friendId} - get a specific friend of a user
    • LINK /users/{id}/friends - add a friend association to this user
    • UNLINK /users/{id}/friends - remove a friend association from this user

    Notice how each level maps to a parent that can be acted upon. Using different parents for the same object is counterintuitive. Retrieving a resource at GET /resource/123 leaves no indication that creating a new resource should be done at POST /resources

    0 讨论(0)
  • 2020-12-02 04:08

    Use Singular and take advantage of the English convention seen in e.g. "Business Directory".

    Lots of things read this way: "Book Case", "Dog Pack", "Art Gallery", "Film Festival", "Car Lot", etc.

    This conveniently matches the url path left to right. Item type on the left. Set type on the right.

    Does GET /users really ever fetch a set of users? Not usually. It fetches a set of stubs containing a key and perhaps a username. So it's not really /users anyway. It's an index of users, or a "user index" if you will. Why not call it that? It's a /user/index. Since we've named the set type, we can have multiple types showing different projections of a user without resorting to query parameters e.g. user/phone-list or /user/mailing-list.

    And what about User 300? It's still /user/300.

    GET /user/index
    GET /user/{id}
    
    POST /user
    PUT /user/{id}
    
    DELETE /user/{id}
    

    In closing, HTTP can only ever have a single response to a single request. A path is always referring to a singular something.

    0 讨论(0)
  • 2020-12-02 04:10

    Why not follow the prevalent trend of database table names, where a singular form is generally accepted? Been there, done that -- let's reuse.

    Table Naming Dilemma: Singular vs. Plural Names

    0 讨论(0)
  • 2020-12-02 04:10

    I don't like to see the {id} part of the URLs overlap with sub-resources, as an id could theoretically be anything and there would be ambiguity. It is mixing different concepts (identifiers and sub-resource names).

    Similar issues are often seen in enum constants or folder structures, where different concepts are mixed (for example, when you have folders Tigers, Lions and Cheetahs, and then also a folder called Animals at the same level -- this makes no sense as one is a subset of the other).

    In general I think the last named part of an endpoint should be singular if it deals with a single entity at a time, and plural if it deals with a list of entities.

    So endpoints that deal with a single user:

    GET  /user             -> Not allowed, 400
    GET  /user/{id}        -> Returns user with given id
    POST /user             -> Creates a new user
    PUT  /user/{id}        -> Updates user with given id
    DELETE /user/{id}      -> Deletes user with given id
    

    Then there is separate resource for doing queries on users, which generally return a list:

    GET /users             -> Lists all users, optionally filtered by way of parameters
    GET /users/new?since=x -> Gets all users that are new since a specific time
    GET /users/top?max=x   -> Gets top X active users
    

    And here some examples of a sub-resource that deals with a specific user:

    GET /user/{id}/friends -> Returns a list of friends of given user
    

    Make a friend (many to many link):

    PUT /user/{id}/friend/{id}     -> Befriends two users
    DELETE /user/{id}/friend/{id}  -> Unfriends two users
    GET /user/{id}/friend/{id}     -> Gets status of friendship between two users
    

    There is never any ambiguity, and the plural or singular naming of the resource is a hint to the user what they can expect (list or object). There are no restrictions on ids, theoretically making it possible to have a user with the id new without overlapping with a (potential future) sub-resource name.

    0 讨论(0)
提交回复
热议问题