如何使用 TypeORM 和 PostgreSQL 构建 Nest.js CRUD REST API

与其他 Node.js 框架类似,Nest.js 提供了一整套工具,用于构建强大且可扩展的后端服务。 尽管如此,理解如何在 Nest.js 中高效地实现创建、读取、更新和删除(CRUD)操作至关重要——这些操作是 API 开发中最基本的功能。

本指南将演示如何使用 TypeORM 和 PostgreSQL 数据库构建 Nest.js CRUD REST API。

Nest.js 入门

首先,安装 Nest.js 命令行工具:

 npm i -g @nestjs/cli 

接下来,通过运行以下命令创建一个新项目:

 nest new crud-app 

命令行工具会提示您选择包管理器;选择您认为最适合的选项。我们在这里使用 npm,也就是 Node 包管理器。

命令行工具将构建一个基础的 Nest.js 项目,其中包含运行应用程序所需的所有配置文件和初始依赖项。

最后,导航到项目目录并启动开发服务器。

 cd crud-app
npm run start

您可以在 GitHub 仓库中找到此项目的源代码。

创建 PostgreSQL 数据库

本教程采用云 PostgreSQL 实例,但您也可以设置本地 PostgreSQL 数据库。 您可以在 Windows、macOS 或 Linux 上安装 PostgreSQL。

设置云 PostgreSQL 实例:

  • 访问 ElephantSQL,注册并登录到您的账户仪表板。
  • 点击页面左上角的“创建新实例”按钮,为您的应用创建一个新实例。
  • 填写您的实例名称,选择免费套餐,最后选择一个区域以完成设置过程。
  • 创建数据库实例后,转到设置页面,然后复制提供的数据库 URL。
  • 配置数据库连接

    在项目根目录下,创建一个 .env 文件并粘贴数据库连接 URL,如下所示:

     DATABASE_URL="<your connection url here>" 

    现在安装以下软件包:

     npm install pg typeorm @nestjs/typeorm @nestjs/config 

    接下来,使用命令行工具创建一个数据库模块。

     nest g module database 

    打开 database/database.module.ts 文件,并添加如下数据库配置代码:

     import { Module } from '@nestjs/common';
    import { ConfigModule, ConfigService } from '@nestjs/config';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { User } from '../users/models/user.entity';

    @Module({
      imports: [
        TypeOrmModule.forRootAsync({
          imports: [ConfigModule],
          inject: [ConfigService],

          useFactory: async (configService: ConfigService) => ({
            type: 'postgres',
            url: configService.get('DATABASE_URL'),
            entities: [User],
            synchronize: true
          }),
        }),
      ],
    })

    export class DatabaseModule {}

    这个数据库模块负责配置 TypeORM 模块,使用必要的连接参数(数据库 URL)进行数据库连接管理。

    另外,它还定义了 User 实体作为配置的一部分,该实体指定了 PostgreSQL 数据库表中存储的数据的结构和属性。

    此时,您的代码可能会抛出错误,因为您还没有创建用户实体。 您将在后续步骤中完成此操作。

    更新 app.module.ts 文件

    最后,更新主应用程序模块,以包含数据库模块的配置。

     import { Module } from '@nestjs/common';
    import { ConfigModule } from '@nestjs/config';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { DatabaseModule } from './database/database.module';

    @Module({
      imports: [
        ConfigModule.forRoot({
          envFilePath: '.env',
        }),
        DatabaseModule,
      ],

      controllers: [AppController],
      providers: [AppService],
    })

    export class AppModule {}

    定义用户模块

    users 模块作为一个核心组件,负责封装和管理实现 API 的 CRUD 功能所需的逻辑。

    运行此终端命令以创建 API 的用户模块。

     nest g module users 

    在创建用户模块的同时,命令行工具也会自动更新 app.module.ts 文件,以反映所做的更改。 这确保了新创建的模块(用户)能够正确集成到应用程序的模块配置中。

    创建用户实体

    TypeORM 是一个对象关系映射 (ORM) 库,它通过将 JavaScript 对象映射到数据库表,简化了在 TypeScript 应用中使用数据库的交互。

    通过使用 TypeORM 创建用户实体,您可以定义 PostgreSQL 数据库中用户数据的结构和属性。

    在 users 目录中,创建一个新的 models/user.entity.ts 文件并添加如下代码。

     import { Entity, PrimaryGeneratedColumn, Column, } from "typeorm";

    @Entity()
    export class User {
        @PrimaryGeneratedColumn()
        id: number;

        @Column()
        name: string;

        @Column()
        email: string;
    }

    用户实体定义了数据库中存储的用户数据的结构。 在本例中,`id` 作为主键列,`name` 和 `email` 列及其相应的属性。

    创建 CRUD API 服务

    现在,通过运行以下命令创建一个 API 服务,它将管理 CRUD 操作的逻辑:

     nest g service users 

    打开 `user-auth.service.ts` 文件并添加如下代码:

     import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Repository } from 'typeorm';
    import {User} from './models/user.entity';

    @Injectable()
    export class UsersService {
      constructor(
        @InjectRepository(User)
        private userRepository: Repository<User>,
      ) {}

      async findAll(): Promise<User[]> {
        return this.userRepository.find();
      }

      async findOne(id: number): Promise<User> {
        return this.userRepository.findOne({ where: { id } });
      }

      async create(user: Partial<User>): Promise<User> {
        const newuser = this.userRepository.create(user);
        return this.userRepository.save(newuser);
      }

      async update(id: number, user: Partial<User>): Promise<User> {
        await this.userRepository.update(id, user);
        return this.userRepository.findOne({ where: { id } });
      }

      async delete(id: number): Promise<void> {
        await this.userRepository.delete(id);
      }
    }

    这个 `UsersService` 类定义了各种专门用于处理 CRUD 操作的 API 方法。 这些方法包括获取所有用户数据、使用 ID 查找特定用户、创建新用户、更新现有用户以及删除数据库中特定用户数据的方法。

    为 API 定义控制器

    创建一个控制器来管理用户相关操作的 API 端点。

     nest g controller users 

    接下来,将以下代码添加到 `users.controller.ts` 文件中。

     import { Controller, Get, Post, Body, Put, Param, Delete, NotFoundException, HttpCode } from '@nestjs/common';
    import { UsersService } from './users.service';
    import { User } from './models/user.entity';

    @Controller('api/users')
    export class UsersController {
      constructor(private readonly usersService: UsersService) {}

      @Get()
      async findAll(): Promise<User[]> {
        return this.usersService.findAll();
      }

      @Post()
      @HttpCode(201)
      async create(@Body() user: User): Promise<User> {
        const createdUser = await this.usersService.create(user);
        return createdUser;
      }

      @Put(':id')
      async update (@Param('id') id: number, @Body() user: User): Promise<any> {
        await this.usersService.update(id, user);
        return { message: 'User updated successfully' };
      }

      @Delete(':id')
      async delete(@Param('id') id: number): Promise<any> {
        const user = await this.usersService.findOne(id);

        if (!user) {
          throw new NotFoundException('User does not exist!');
        }

        await this.usersService.delete(id);
        return { message: 'User deleted successfully' };
      }
    }

    控制器管理用户操作的 API 端点。 它处理 GET 请求以检索所有用户、POST 请求以创建新用户、PUT 请求以更新现有用户以及 DELETE 请求以删除用户。

    通过利用 `UsersService` 并与 `User` 实体交互,该控制器提供了一个完整的 API,用于管理对数据库中存储的数据的用户相关操作。

    更新 users.module.ts 文件

    最后,如下更新 `users.module.ts` 文件,以确保合并 `User` 实体和 TypeORM 模块,该模块建立与数据库的连接。

     import { Module } from '@nestjs/common';
    import { UsersController } from './users.controller';
    import { UsersService } from './users.service';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { User } from './models/user.entity';

    @Module({
      imports: [TypeOrmModule.forFeature([User])],
      controllers: [UsersController],
      providers: [UsersService]
    })

    export class UsersModule {}

    最后,启动开发服务器以使用 Postman 测试 CRUD 操作。

     npm run start 

    服务器将在端口 3000 上启动,您可以通过以下网址发送 API 请求: http://localhost:3000/api/users

    使用 Nest.js 构建后端应用程序

    无论是开发简单的 REST API 还是复杂的 Web 应用程序,Nest.js 都提供了一系列全面的特性和功能,可以帮助您构建可靠且强大的后端系统。

    Nest.js 提供了比 Express.js 更结构化的项目开发方法。 得益于其有组织的模块化设计模式,这使得您可以自信地构建、扩展和维护复杂的应用程序。