commercetools / commercetools-sdk-java-v2

The e-commerce SDK from commercetools for Java.
https://commercetools.github.io/commercetools-sdk-java-v2/javadoc/index.html
Apache License 2.0
34 stars 15 forks source link

Interface for ProjectApiRoot to enable multi-tenancy #403

Closed pintomau closed 1 year ago

pintomau commented 1 year ago

Is your feature request related to a problem? Please describe. We want to be able to streamline multi-tenant capability in our platform.

With SDK V1, we were able to do this via an object pool, behind the BlockingSphereClient interface. This enabled us to dispatch to the right client via an InvocationHandler that handled the tenant discovery logic. This way, we can inject BlockingSphereClient directly without worrying about tenancy logic on a daily basis.

Describe the solution you'd like Either create an interface for ProjectApiRoot, or some other way to streamline this.

Describe alternatives you've considered Extracting an interface out of ProjectApiRoot and decorate the real ProjectApiRoot.

cglib or bytebuddy are also options, but easier solutions exist, especially if we want to consider native support in the future...

Maybe other middleware oriented solutions could exist, but doesn't seem to be quite the level of abstraction we need to be able to further control scoping, middlewares per tenant, etc...

Additional context NA

jenschude commented 1 year ago

There are multiple possible solutions to do this right away. I added a test to handle multi tenancy in 34c7089

One solution is to create the different ApiHttpClient instances for each tenant and then create the ProjectApiRoot when needed. The creation should not come with costs as the ProjectApiRoot just hold a reference to the Client and the project key. This could also be used with a request scoped dependency injection:

final MultiTenantClient client = new MultiTenantClient();
client.add("tenant1", "tenant1-project-key", client1);
client.add("tenant2", "tenant2-project-key", client2);

client.get("tenant1").get().executeBlocking();
client.get("tenant2").get().executeBlocking();

The second option is to create an ProjectApiRoot instance which uses a ApiHttpClient instance that is selecting the underlying client without providing a project client.

final InvocationHandler client = new InvocationHandler();
client.add("tenant1", client1);
client.add("tenant2", client2);

ProjectApiRoot projectApiRoot = ProjectApiRoot.fromClient("", client);
projectApiRoot.get().executeBlocking();

And the third one is to use a ProjectApiRoot which only serializes and the build request command is executed by the ApiHttpClient instance. This comes close to the v1 behavior you described.

ProjectApiRoot projectApiRoot = ProjectApiRoot.of("");
client.execute(projectApiRoot.get()), Duration.ofSeconds(10));
jenschude commented 1 year ago

We will nevertheless introduce a ProjectScopedApiRoot interface

Please see https://github.com/commercetools/commercetools-sdk-java-v2/pull/405

pintomau commented 1 year ago

Yeah, solution two seems to be close to what we want.

But with the interface now it should be easier to migrate.

Thank you.