Search code examples
restuser-interfaceapi-design

REST URL Design considerations


I'm in charge of designing a routing system (along with the URL structure) for a relatively small app. The app itself should provide with the functional for adding "root" level entities as well as the ability to add child (nested) entities from the context of their parents.

Considering the following sample setup:

  • Root entity: Dogs.
  • Child entity: Vaccinations

I'm having the following UI routing (the BE routing is easy as it's always flat and I can use VERBs to my advantage):

NOTE: The chances for getting more than 1 level of nesting are pretty immaterial, but if they will materialize, it might become an issue...

Root level:

  • GET: /dogs?param1=value1&...
  • POST: /dogs/add
  • PUT: /dogs/10/update
  • DELETE /dogs/10/delete
  • CUSTOM /dogs/10/custom

Nested level:

  • GET: /dogs/10/vaccinations?param1=value1&...
  • POST: /dogs/10/vaccinations/add
  • PUT: /dogs/10/vaccinations/25/update
  • DELETE: /dogs/10/vaccinations/25/delete
  • CUSTOM: /dogs/10/vaccinations/25/custom

While this works for me, I can see another approach afloat whereby instead of:

/dogs/10/vaccinations/25/add

people would use:

/dogs/10/addvaccination/25

which results in a slightly shorter URL but incurs the processing overhead related to stepping away from resource notation - i.e addvaccination needs to be converged to vaccinations + add.

I know REST is only a recommendations set, so I'd like to see what people think about my original approach and possibly gather any additional concerns/suggestions.


Solution

    1. REST doesn't care what spelling you choose for your resource identifiers. So long as you comply with the production rules in RFC 3986, your resource identifiers are fine. For HTTP specifically, the constraint is a little bit tighter; see RFC 9110. You will make life a lot easier for people if you choose spellings that can support URI templates; see RFC 6570

    2. Your resource model is not your domain model or data model. Think "document about dog 10" rather than "dog 10".

    3. Having a distinct resource for each HTTP method makes general purpose caching harder. If the purpose of an HTTP request is to modify the document about dog 10, you really want the spelling of the URI to be the same as that used to fetch a copy of the document about dog 10.

    GET /dogs/10
    PUT /dogs/10
    DELETE /dogs/10
    

    See RFC 9111 for details about the impact of unsafe methods and caching.

    1. REST doesn't care about "nesting"
    /dogs/10
    /dogs/10/vaccinations
    

    As far as REST/HTTP are concerned, these are two different resources, and they need not be related to each other in any way.

    REST and HTTP both give us a lot of freedom in how we design our URI; we can use some of that freedom to choose spellings that are easy for human beings to map to the semantics of the resource itself, but the machines don't care.

    The machines do know about reference resolution and dot segments (see RFC 3986), so it is reasonable to consider URI spelling conventions that simplify relative references to related documents. For example, compare:

    /dogs/10/vaccinations * .. = /dogs/10
    /vaccinations/dogs/10 * .. = /vaccinations/dogs
    

    /vaccinations/dogs/10 is fine, and machines will do the right thing, but the options afforded by /dogs/10/vaccinations are probably more useful.