I want to connect to any database based on the subdomain (multi-tenant), but i\'m not sure how can i do it.
My code runs when the app is started, but i don\'t know
We also have a Mulit-Tenancy Setup for our NestJS Setup.
You could have a middleware that decides, depending on the request, which datasource to use. In our example we are using TypeORM which has a pretty good integration in NestJS. There are some useful functions within the TypeORM package.
export class AppModule {
constructor(private readonly connection: Connection) {
}
configure(consumer: MiddlewareConsumer): void {
consumer
.apply(async (req, res, next) => {
try {
getConnection(tenant);
next();
} catch (e) {
const tenantRepository = this.connection.getRepository(tenant);
const tenant = await tenantRepository.findOne({ name: tenant });
if (tenant) {
const createdConnection: Connection = await createConnection(options);
if (createdConnection) {
next();
} else {
throw new CustomNotFoundException(
'Database Connection Error',
'There is a Error with the Database!',
);
}
}
}
}).forRoutes('*');
}
This is an example of our middleware. TypeORM is managing the connections internally. So the first thing you would try is to load the connection for that specific tenant. If there is one, good otherwise just create one. The good thing here is, that once created the connection stays available in the TypeORM connection manager. This way you always have a connection in the routes.
In your routes you need a identification for your tenants. In our case it is just a string which is extracted from the url. Whatever value it is you can bind it to the request object inside your middleware. In your controller you extract that value again and pass it to your services. Then you have to load the repository for your tenant and your good to go.
@Injectable()
export class SampleService {
constructor() {}
async getTenantRepository(tenant: string): Promise> {
try {
const connection: Connection = await getConnection(tenant);
return connection.getRepository(Property);
} catch (e) {
throw new CustomInternalServerError('Internal Server Error', 'Internal Server Error');
}
}
async findOne(params: Dto, tenant: string) {
const entityRepository: Repository = await this.getTenantRepository(tenant);
return await propertyRepository.findOne({ where: params });
}
That's what a service looks like in our application.
Hopefully this will inspire you and get you going with your problem :)