我如何构建我的 REST API

2025-06-07

我如何构建我的 REST API

这篇文章最初发表在我的博客上。


当我开始使用Node.js在服务器端构建 REST API 时,我一次又一次地被同样的问题困扰:

文件夹结构应该是什么样的?

显然,这个问题没有完美或 100% 正确的答案,但在阅读了一些相关的文章后,我找到了一个非常符合我需求的文件夹结构和架构。所以今天我想向大家展示我是如何构建和组织我的 Node.js REST API 的。

我还发布了一个 GitHub存储库,其中包含一个示例应用程序,您可以将其用作您自己项目的模板。

需要说明的是,我使用Express.js作为 Web 框架,并使用TypeORM作为 ORM。将此文件夹结构应用于其他框架应该也不难。

该架构主要基于组件,这使得我们能够更轻松地只请求真正需要的数据。例如,我们有一个User包含所有用户信息的组件。

让我们从root目录开始。

目录:根目录

expressjs-api
└───db
└───dist
└───logs
└───node_modules
└───src
│   README.md
│   ...
Enter fullscreen mode Exit fullscreen mode

src这个结构没什么特别的,对你来说应该不陌生。它实际上是一个基本的 Node.js 设置。这里有趣的部分是这篇文章所讨论的文件夹的内容。

那么我们这里有什么?

expressjs-api
└───src
   └───api
   │   │
   │   └───components
   │   │
   │   └───middleware
   │   │
   │   │   routes.ts
   │   │   server.ts
   └───config
   └───services
   └───test
   |
   │   app.ts
Enter fullscreen mode Exit fullscreen mode

从这里开始,我们将自上而下地逐一介绍文件/目录,并逐一进行解释。首先从api目录开始,它是应用程序最重要的部分。

目录:src/api/components

expressjs-api
└───src
    └───api
        └───components
            └───article
            └───auth
            └───country
            └───user
            │   helper.ts
            │   index.ts
Enter fullscreen mode Exit fullscreen mode

这里我们可以看到基于组件的 Node API 的核心。每个组件都有自己的路由控制器模型存储库策略测试模板

让我们进入User组件看看吧。

目录:src/api/components/user

expressjs-api
└───src
    └───api
        └───components
            └───user
                └───services
                |   │   mail.ts
                └───templates
                |   │   confirmation.html
                |   |   invitation.html
                │   controller.ts
                │   model.ts
                │   policy.json
                │   repository.ts
                │   routes.ts
                │   user.spec.ts
Enter fullscreen mode Exit fullscreen mode

如你所见,组件由我之前提到的文件组成。它们大多数代表一个导出的。当然,你可以在这里添加更多组件特定的内容。

由于我有多个组件,并且它们的类大多数情况下具有相同的结构,因此我还创建了在类中实现的接口。这有助于我保持组件结构的一致性。

此外,我们services这里的目录包括本地组件服务mail,例如来自全局服务的交互服务。

templates目录包含指定组件的邮件 HTML 模板。对于动态渲染 HTML 代码,我强烈推荐ejs

控制器.ts

控制器类处理传入的请求并将响应数据发送回客户端。它使用该类repository与数据库进行交互。请求验证通过中间件在执行前几步进行。

一个简短的例子:

export class UserController {
  private readonly repo: UserRepository = new UserRepository()

  async readUser(
    req: Request,
    res: Response,
    next: NextFunction
  ): Promise<Response | void> {
    try {
      const { userID } = req.params

      const user: User | undefined = await this.repo.read({
        where: {
          id: +userID,
        },
      })

      return res.json(user)
    } catch (err) {
      return next(err)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

模型.ts

该模型代表其组件的数据库模型。在我的例子中,它是一个TypeORM类。它主要由类使用repository

策略.json

此 json 文件包含每个用户角色对指定组件的访问权限。它是基于访问控制列表系统的一部分。

例子:

{
  "Admin": [{ "resources": "user", "permissions": "*" }],
  "User": [{ "resources": "user", "permissions": ["read"] }]
}
Enter fullscreen mode Exit fullscreen mode

存储库.ts

存储库类就像数据库的包装器。在这里,我们可以读写数据库中的数据。此外,我们还可以实现缓存等功能。

您可以将该repository类导入到任何其他文件中,并从数据库中查询该组件的数据。此外,由于我们不必多次重写 SQL 语句,因此它可以避免编写冗余代码。

由于大多数组件存储库都需要相同的基本访问方法,例如readAll、和readsave因此delete我使用了一个包含所有这些方法的通用父类。这节省了大量代码。

请参阅AbsRepository了解具体实现。

路线.ts

这里我们定义了相应组件的API端点controller,并为其分配方法。此外,我们还可以添加更多内容,例如

  • 授权(例如 JWT)
  • 权限检查(ACL)
  • 请求主体验证
  • 组件特定的中间件在这里。

简短的例子:

class UserRoutes implements IComponentRoutes<UserController> {
  readonly name: string = "user"
  readonly controller: UserController = new UserController()
  readonly router: Router = Router()
  authSerivce: AuthService

  constructor(defaultStrategy?: PassportStrategy) {
    this.authSerivce = new AuthService(defaultStrategy)
    this.initRoutes()
  }

  initRoutes(): void {
    this.router.get(
      "/:userID",
      this.authSerivce.isAuthorized(),
      this.authSerivce.hasPermission(this.name, "read"),
      param("userID").isNumeric(),
      this.authSerivce.validateRequest,
      this.controller.readUser
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

用户规范.ts

这是用于测试组件及其端点的测试文件。您可以在此处阅读有关测试此架构的更多信息。

目录:src/api/middleware/

expressjs-api
└───src
    └───api
        └───middleware
            │   compression.ts
            │   loggin.ts
Enter fullscreen mode Exit fullscreen mode

此文件夹包含所有 API 的全局中间件,如压缩、请求日志等。

文件:src/api/routes.ts

expressjs-api
└───src
    └───api
        │   routes.ts
Enter fullscreen mode Exit fullscreen mode

server这里我们注册了所有组件和中间件的路由。这些路由稍后会在类中使用。

文件:src/api/server.ts

expressjs-api
└───src
    └───api
       │   server.ts
Enter fullscreen mode Exit fullscreen mode

这里我们声明了 Express.js 服务器所需的一切:

  • 导入中间件
  • 导入路线
  • 错误处理

稍后,我们server也可以导入该类进行单元测试。

目录:src/config

expressjs-api
└───src
    └───config
       │   globals.ts
       │   logger.ts
       │   permissions.ts
Enter fullscreen mode Exit fullscreen mode

此目录包含 API 的配置文件。例如:

  • 全局变量
  • 记录器配置
  • ACL权限
  • SMTP 配置

请随意将任何与配置相关的文件放在这里。

目录:src/services/

该目录包含我们可能需要的全局服务,例如授权、发送邮件缓存辅助方法。

expressjs-api
└───src
    └───services
        │   auth.ts
        │   helper.ts
        │   mail.ts
        |   redis.ts
Enter fullscreen mode Exit fullscreen mode

授权.ts

在这里,我们设置应用程序的护照策略等内容并定义授权方法。

助手.ts

辅助类包含用于散列UUID等的辅助方法。

邮件.ts

该服务用于发送邮件和渲染组件的模板。再次推荐ejsrenderFile的功能

目录:src/test/

此目录包含用于运行组件测试的测试工厂。您可以在此处
阅读更多相关信息

文件:src/app.ts

这是我们应用程序的启动文件。它初始化数据库连接并启动 Express 服务器。

expressjs-api
└───src
    │   app.ts
Enter fullscreen mode Exit fullscreen mode

全部在一起

最后但同样重要的是项目结构的完整概述:

expressjs-api
└───src
    └───config
    │   │   globals.ts
    │   │   logger.ts
    │   │   permissions.ts
    └───api
    │   │
    │   └───components
    │   │   │
    │   │   └───article
    │   │   │
    │   │   └───user
    |   │   │   │
    |   │   │   └───templates
    |   │   │   |   │   confirmation.html
    |   │   │   |   │   invitation.html
    │   │   |   │   controller.ts
    │   │   |   │   model.ts
    │   │   |   │   policy.json
    │   │   |   │   repository.ts
    │   │   |   │   routes.ts
    │   │   |   │   user.spec.ts
    │   │
    │   └───middleware
    │   │   │   compression.ts
    │   │   │   logging.ts
    │   │
    │   │   routes.ts
    │   │   server.ts
    └───services
    └───test
    |
    │   app.ts
Enter fullscreen mode Exit fullscreen mode

就是这样!希望这能给那些不知道如何构建 Node.js 应用程序或不知如何入门的人一些帮助。我认为还有很多事情可以做得更好或更高效。

如果您有兴趣为 Node.js REST API 编写单元测试,请查看这篇涵盖相同架构的文章。

我还发布了一个包含示例应用程序的 GitHub 仓库。可以看看

文章来源:https://dev.to/larswaechter/how-i-struct-my-rest-apis-11k4
PREV
2023 年如何成为更优秀开发者的 20 条建议
NEXT
TypeScript:简化形式与 JS 的超级结合。