Nest/TypeORMを介してSAAS製品を構築しようとしていますが、サブドメインごとにデータベース接続を構成/変更する必要があります。
customer1.domain.com => connect to customer1 database
customer2.domain.com => connect to customer2 database
x.domain.com => connect to x database
どうやってやるの ?インターセプターまたはリクエストコンテキスト(またはZone.js)を使用しますか?
どうやって始めたらいいのかわからない。誰かがすでにそれをしていますか?
WIP:私が現在行っていること:
すべてのルートにミドルウェアを作成して、サブドメインをres.locals
(インスタンス名)に挿入し、typeorm接続を作成/警告します
import { Injectable, NestMiddleware, MiddlewareFunction } from '@nestjs/common';
import { getConnection, createConnection } from "typeorm";
@Injectable()
export class DatabaseMiddleware implements NestMiddleware {
resolve(): MiddlewareFunction {
return async (req, res, next) => {
const instance = req.headers.Host.split('.')[0]
res.locals.instance = instance
try {
getConnection(instance)
} catch (error) {
await createConnection(instance)
}
next();
};
}
}
コントローラ内:@Responseからインスタンス名を取得し、それをサービスに渡します
@Controller('/catalog/categories')
export class CategoryController {
constructor(private categoryService: CategoryService) {}
@Get()
async getList(@Query() query: SearchCategoryDto, @Response() response): Promise<Category[]> {
return response.send(
await this.categoryService.findAll(response.locals.instance, query)
)
}
サービス中:指定されたインスタンスのTypeORM Managerを取得し、リポジトリを介してデータベースをクエリします
@Injectable()
export class CategoryService {
// constructor(
// @InjectRepository(Category) private readonly categoryRepository: Repository<Category>
// ) {}
async getRepository(instance: string): Promise<Repository<Category>> {
return (await getManager(instance)).getRepository(Category)
}
async findAll(instance: string, dto: SearchCategoryDto): Promise<Category[]> {
let queryBuilder = (await this.getRepository(instance)).createQueryBuilder('category')
if (dto.name) {
queryBuilder.andWhere("category.name like :name", { name: `%${dto.name}%` })
}
return await queryBuilder.getMany();
}
それはうまくいくようですが、私はほとんどすべてについて確信がありません:
Response.send()+ Promise + await(s)+ passサブドメインをどこでも処理するのは楽しいことではありません...
サブドメインをサービスに直接取得する方法はありますか?
正しいサブドメイン接続/リポジトリをサービスに直接取得して、コントローラーに挿入する方法はありますか?
Yohのソリューションに触発されましたが、NestJSの新機能に合わせて少し調整しました。その結果、コードが少なくなります。
1)DatabaseMiddleware
を作成しました
import { Injectable, NestMiddleware, Inject } from '@nestjs/common';
import { getConnection, createConnection, ConnectionOptions } from "typeorm";
@Injectable()
export class DatabaseMiddleware implements NestMiddleware {
public static COMPANY_NAME = 'company_name';
async use(req: any, res: any, next: () => void) {
const databaseName = req.headers[DatabaseMiddleware.COMPANY_NAME];
const connection: ConnectionOptions = {
type: "mysql",
Host: "localhost",
port: 3307,
username: "***",
password: "***",
database: databaseName,
name: databaseName,
entities: [
"dist/**/*.entity{.ts,.js}",
"src/**/*.entity{.ts,.js}"
],
synchronize: false
};
try {
getConnection(connection.name);
} catch (error) {
await createConnection(connection);
}
next();
}
}
2)main.tsではすべてのルートに使用します
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(new DatabaseMiddleware().use);
...
3)稼働中の取得接続
import { Injectable, Inject } from '@nestjs/common';
import { Repository, getManager } from 'typeorm';
import { MyEntity } from './my-entity.entity';
import { REQUEST } from '@nestjs/core';
import { DatabaseMiddleware } from '../connections';
@Injectable()
export class MyService {
private repository: Repository<MyEntity>;
constructor(@Inject(REQUEST) private readonly request) {
this.repository = getManager(this.request.headers[DatabaseMiddleware.COMPANY_NAME]).getRepository(MyEntity);
}
async findOne(): Promise<MyEntity> {
return await this.repository
...
}
}