Wow, that title is a mouthful of acronyms. In my continuing journey with developing Collabinate, a Multitenant RESTful API for building activity streams, I have come to a place where I need to decide how to route my clients to the correct resource. There is a potential problem because resource identifiers can in theory be duplicated across tenants (user accounts). This means I need to decide whether or not to include some kind of identifier per tenant in the URIs for the service, or find some other way to have the code route the requests. There seem to be three schools of thought on this. I’ll break down all three with pros and cons. Let’s assume a tenant with an ID of
1. Tenant? What Tenant?
The first option is to not change the URI at all, and use only metadata to identify the tenant, as such:
The rationale behind this is that the tenant can be identified in headers, or via the authentication mechanism such as OAuth 2.0 with bearer tokens.
- Keeps the URI “clean”. I’m not sure what this means regarding an API that will mostly be used by machines, but we’ll go with it.
- Allows full URIs to be used in documentation or configuration without per-tenant modifications.
- Allows a client that can generate the appropriate metadata to access the same resource across multiple tenants without changing the URI. In theory this could be good for administration tasks.
- Avoids the need for dealing with the tenant in the path space in code, which keeps things simpler.
- This can mess with cache-ability. Any proxy that caches the resource will need the ability to pass the metadata to the origin.
- The ability to access more than one tenant at a time becomes difficult. For example, if you’re using the auth mechanism above, you need a separate token to access each tenant.
- You need to deal with getting your tenant info in code in a separate and much different way than your resource information.
2. Subdomain Mania
The second option is to include the client ID in the authority (the DNS host name), like this:
This entails setting up a DNS entry for each tenant and handling the routing by reading the authority in code, or rerouting before it gets there.
- Having their own domain name gives users a strong sense of ownership.
- This is the easiest method to handle QoS issues – if the client needs special treatment just put them on a special server and point the DNS there.
- Also keeps the tenant out of the path space like #1 above, which can keep the code simpler.
- Cookies can be used at the “service” level (
example.com) or at the tenant level (
- URL rewriting can be used on the server to combine the benefits of both this method (#2) and #3 below.
- DNS provisioning and management can become a chore. This is especially true as your user base grows if parts of it are manual.
- This usually requires wildcard SSL certificates, which aren’t as well supported as single host certs.
- Depending on your network layout, cache-ability can still be an issue.
- The ability to have users authorized across multiple tenants (e.g. super users or admins) can be a pain.
The final option is to include the tenant ID as part of the URI path, like the following:
The idea here is that
/some/path can actually represent different resources based on tenant, so the URI should be as explicit as possible in identifying those resources. This is achieved by including all information needed for resource identification in the URI, specifically the tenant ID. Do note that for security reasons, you’ll likely want to expose a surrogate or slug instead of an actual database ID for the tenant.
- Clarity. Ain’t nothin’ like having it spelled out for you.
- You can route based on tenant in the URI right from the load balancer.
- You can do special mapping based on special tenant IDs, e.g
defaultto match the tenant for the current authenticated tenant or
adminfor super users.
- The code can remain FQDN agnostic, at least for tenant identification reasons.
- URIs may be longer. Boo-hoo.
- URIs are different for every tenant. This might be a pain with documentation or configuration.
- Tools that access multiple tenants must utilize different URIs even for resources that are conceptually the same across tenants.
After weighing these, it seems best to start with option 3, then move to option 2 with routes to the way you had option 3 set up if and when needed. Option 1 seems painful for services that are built to be multitenant from the start, but if you have good arguments for it, please let me know in the comments. Happy API coding!
Latest posts by Jack Jones (see all)
- Salesforce API Testing with Username-Password Authentication - 2014-12-10
- Being Human - 2014-01-21
- Why Are You An Entrepreneur? - 2013-11-09