RESTier icon indicating copy to clipboard operation
RESTier copied to clipboard

[2.0] Multi-Tenancy

Open mottibec opened this issue 6 years ago • 5 comments

we are converting our RESTier server to a Multi-tenant server and I was wondering if RESTier has support for that. is there a built-in way to register an EDM model per tenant? and if not what would be the best way to approach this?

some background: our RESTier servers are serving as middleware between our front-end apps and Microsoft CDS, until now we supported only one CDS instance per server but now we must support a multi-tenant architecture

mottibec avatar Feb 18 '20 09:02 mottibec

This is a great question, unfortunately, I don't believe that Restier is abstracted enough to be able to address different EDM models at different URLs. Now, if it was the exact same data model, just different connection strings, I believe that would be possible. But the Model lookup routines in Restier are not ideal, and I ran into problems before when I had different data models under the same service. I can't recall if I fixed it or not.

Sorry if that is not more helpful.

robertmclaws avatar Feb 19 '20 04:02 robertmclaws

after some trial and error I got the following startup code working, not sure if it works 100% yet

            var tenants = GetTenants();
            string currentTenantId = null;

            config.UseRestier<CdsApi>(services =>
            {
                var tenantId = currentTenantId;
                services.TryAddScoped(sp =>
                {
                    var id = tenantId;
                    return tenants.First(t => t.Id == id);
                });
            });

            foreach (var tenant in tenants)
            {
                currentTenantId = tenant.Id;
                config.MapRestier<CdsApi>($"restier{tenant.Name}", $"{tenant.Name}/api", true);
            }

and in the model builder

var svc = context.GetApiService<CdsApi>();
var tenant = svc.TenantInfo;
tenant.Entities ....

mottibec avatar Feb 19 '20 08:02 mottibec

Hey that looks like it could work! Sounds like what's going to be really important here is unit test coverage of the API... you should look at the unit tests here to see how we leverage a library I wrote called Breakdance to help test Restier methods. You will probably want to do something similar to make sure your tenant-based APIs are working.

Also, you'll want to make sure you're always using .FirstOrDefault() and then check for null, otherwise you might get a runtime exception on the API, and that would probably be bad for your customers.

HTH! 👊

robertmclaws avatar Feb 20 '20 16:02 robertmclaws

Let's make sure we have at least one solid approach for multi-tenancy in Restier 2.0.

robertmclaws avatar Dec 05 '23 16:12 robertmclaws

Hello @robertmclaws,

I managed to configure the RESTier library to work with multitenant (different databases) in the following way:

1 - Creating a middleware to get from the api route the tenant identifier; 2 - When registering the api, adding to the dependency injection container the ability to access the http context, and configuring my DBContext by scope, being created using a delegate (Func<IServiceProvider, DBContext>). The delegate implementation will parse the HttpContext to determine which tenant the DBContext should be created on. 3 - Register an api route for each tenant, adding the tenant identifier to the route (which will be used in the middleware).

Apparently it worked correctly, let me know if this approach has been tested before, and if it can be considered safe.

rafaelbastos29 avatar Apr 09 '24 13:04 rafaelbastos29