REST - supporting multiple possible identifiers

后端 未结 5 1153
一向
一向 2020-12-13 02:00

For the site I am working on, we are in the process of improving our URLs for one type of resource - specifically, moving away from numerical IDs toward unique, descriptive

相关标签:
5条回答
  • 2020-12-13 02:06

    Your API is not RESTful if this is an issue. To quote Roy Fielding:

    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 REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

    0 讨论(0)
  • 2020-12-13 02:17

    Quite an old question but I had the same and finnaly found the solution : use regex in your path param.

    Here's how I coded that use case

    @GET
    @Path("/{id : \\d+}")
    @Produces(APPLICATION_JSON)
    public Response getById(@PathParam("id") long id) {
     <<your code>>
    }
    
    @GET
    @Path("/{name}")
    @Produces(APPLICATION_JSON)
    public Response getByName(@PathParam("name") String name) {
     <<your code>>
    }
    
    0 讨论(0)
  • 2020-12-13 02:19

    I think adding a path segment/prefix is the best answer. Since these are unique secondary keys, this isn't the same as search (which returns a set of items), so using query parameters (which aren't cached) doesn't seem like the best choice.

    Personally, I plan to use a path segment prefix delimited by "=", like "name=" or "email=":

    user/123456
    user/name=john.doe
    user/email=john.doe@john.doe
    

    This is functionally equivalent to adding a path segment (e.g. "user/name/john.doe"), but feels to me like it maps more closely to the conceptual model. Of course, this is an insignificant detail, since RESTful APIs shouldn't specify a fixed URI structure anyway.

    Not using query parameters also allows sub-resources to be accessed naturally:

    user/name=john.doe/inbox/df87bhJXrg63
    

    Frameworks like Java's JAX-RS support using whatever delimiter you want:

    @GET
    @Path("user/{id}")
    User getUser(@PathParam("id") UUID id);
    
    @GET
    @Path("user/name={name}")
    User getUserByName(@PathParam("name") String name);
    
    @GET
    @Path("user/email={email}")
    User getUserByEmail(@PathParam("email") String email);
    
    0 讨论(0)
  • 2020-12-13 02:23

    I'd consider qualifying the string with an optional suffix:

    /users/48573/id
    
    /users/48573/name
    

    If you receive a string without the suffix:

    /users/48573
    

    then you check the string and see if it's an ID or Name.

    If you only get a valid ID but not a name then it's a retrieval by ID equivalent to:

    /users/48573/id
    

    If you only get a name back then it's a retrieval by Name equivalent to:

    /users/48573/name
    

    If you can retrieve the value by ID or Name then you return a 300 response error and return links to both possiblities to the client:

    /users/48573/id
    
    /users/48573/name
    

    The legacy consumers continue to work 'as is' except for the occasional occurence of duplicate ID/name pairs where they receive the new 300 response error.

    0 讨论(0)
  • 2020-12-13 02:27

    Your first option is probably the best.

    Searching for users by ID:

    /users/id/48573
    

    Searching for users by short name:

    /users/name/thisisausername
    

    If they leave out that path parameter, you could always default to your new short username format.

    Another option that I have seen quite a bit is to use query parameters like the following:

    /users?id=48573
    /users?name=thisisausername
    

    I think the first looks a bit cleaner and more readable.

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