我正在为多个客户创建一个API。像/users
每个客户一样使用核心端点,但是某些端点依赖于单独的自定义。因此,可能是用户A需要一个特殊的终结点,/groups
而其他客户将没有该功能。就像附带说明一样,由于这些额外功能,每个客户也将使用自己的数据库架构。
我个人使用NestJs(引擎盖下的Express)。因此,app.module
当前注册了我所有的核心模块(带有自己的端点等)。
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module'; // core module
@Module({
imports: [UsersModule]
})
export class AppModule {}
我认为这个问题与NestJs无关,因此您在理论上将如何处理?
我基本上需要一个能够提供基本系统的基础架构。由于每个扩展都是唯一的,/users
因此可能不再存在核心端点。开发新功能时,不应触摸核心应用程序。扩展应自行集成或在启动时进行集成。核心系统没有端点,但将从这些外部文件扩展。
我想到了一些主意
第一种方法:
每个扩展都代表一个新的存储库。定义一个包含所有扩展项目的自定义外部文件夹的路径。此自定义目录将包含一个groups
带有groups.module
import { Module } from '@nestjs/common';
import { GroupsController } from './groups.controller';
@Module({
controllers: [GroupsController],
})
export class GroupsModule {}
我的API可能会遍历该目录并尝试导入每个模块文件。
优点:
- 定制代码远离核心存储库
缺点:
NestJs使用Typescript,因此我必须先编译代码。我将如何管理API构建以及来自自定义应用的构建?(即插即用系统)
自定义扩展非常宽松,因为它们仅包含一些打字稿文件。由于他们无权访问API的node_modules目录,因此我的编辑器将向我显示错误,因为它无法解析外部程序包依赖性。
某些扩展程序可能会从另一个扩展程序中获取数据。群组服务可能需要访问用户服务。这里的事情可能会变得棘手。
第二种方法: 将每个扩展名保留在API的src文件夹的子文件夹中。但是将此子文件夹添加到.gitignore文件中。现在,您可以将扩展保留在API中。
优点:
您的编辑器能够解决依赖关系
在部署代码之前,您可以运行build命令,并且将具有单个分发
您可以轻松访问其他服务(
/groups
需要通过ID查找用户)
缺点:
- 开发时,必须将存储库文件复制到该子文件夹中。更改某些内容后,您必须将这些文件复制回去,并用更新的文件覆盖您的存储库文件。
第三种方法:
在外部自定义文件夹中,所有扩展都是完全独立的API。您的主要API仅提供身份验证内容,并且可以充当代理,将传入的请求重定向到目标API。
优点:
- 可以轻松开发和测试新扩展
缺点:
部署将很棘手。您将有一个主API和n个扩展API,它们将启动各自的进程并监听端口。
代理系统可能很棘手。如果客户端请求
/users
代理,则需要知道哪个扩展API侦听该端点,然后调用该API并将该响应转发回客户端。为了保护扩展API(身份验证由主API处理),代理需要与这些API共享机密。因此,扩展API仅在代理提供了匹配的机密时才传递传入的请求。
第四种方法:
微服务可能会有所帮助。我从这里获得了指南https://docs.nestjs.com/microservices/basics
我可以有一个用于用户管理,组管理等的微服务,并通过创建一个调用这些微服务的小型api /网关/代理来使用这些服务。
优点:
可以轻松开发和测试新扩展
分开关注
缺点:
部署将很棘手。您将拥有一个主要的API和n个微服务来启动自己的进程并监听端口。
如果要自定义,似乎必须为每个客户创建一个新的网关api。因此,除了扩展应用程序之外,我每次都必须创建一个自定义的消费API。那不会解决问题。
为了保护扩展API(身份验证由主API处理),代理需要与这些API共享机密。因此,扩展API仅在代理提供了匹配的机密时才传递传入的请求。