Goal
I'm attempting to build a multi-tenant application with Feathers JS. On login, the tenant ID will be included in the request. From then on, the tenant ID will be gotten from the user
field with the request parameters. Every user has this tenantId
field.
In MongoDB, I have one unique collection of every data type per tenant. The collection names look like tenantId.documents
and tenantId.users
Problem
The service generated via the feathers generate service
CLI command looks like so:
export class Documents extends Service {
//eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(options: Partial<MongoDBServiceOptions>, app: Application) {
super(options);
const client: Promise<Db> = app.get('mongoClient');
client.then(db => {
this.Model = db.collection('documents');
});
}
}
As you can see, the generated Service
s seem to need their collection name ("documents" in this case) during instantiation. Normally, this makes sense since it saves time await
ing a call to app.get("mongoClient")
However, since I need to dynamically change which collection I read from based on the User's tenantId
, this won't work for me.
I implemented something like the following:
export class Documents extends Service {
client: Promise<Db>
//eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(options: Partial<MongoDBServiceOptions>, app: Application) {
super(options);
this.client = app.get("mongoClient");
}
async create(data: IDocumentData, params: Params) {
const db: Db = await this.client;
this.Model = db.collection(`${params.user!!.organizationId}.documents`);
return super.create(data, params);
}
}
The problems are these:
- I need to
await this.client
every request, even when the promise will probably already be fulfilled by the time a user actually makes a request to this service - I have to implement every method of the parent
Service
even though I barely need to add any real functionality.
Question
What is the most feathers-y way to solve this problem?
- I don't want to override every method that I need in every service
- I don't see a way to handle this with middleware or hooks.
- I also don't think it's necessary to create one service instance per tenant in my application. It seems wasteful since I don't need to make any additional external requests based on the tenant ID, I just need to change the collection
Is there a good, pretty way to do this in Feathers?