用 NestJS 搭建服务端 CRUD 应用并接入 refine从零到可运行的实战指南【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine本篇技术指南以 refine 开源仓库官方博客的 NestJS 入门教程为骨架完整讲解 NestJS 框架的安装、三大核心组件Module、Controller、Provider与一个车辆管理应用auto-garage-nest的逐步实现并在文末延伸介绍 refine 官方对 NestJS 生态的两大数据提供器NestJS CRUD 与 NestJS Query。读完本文你将能够独立搭建一个基于 TypeScript TypeORM SQLite 的 RESTful CRUD 后端并理解如何将这类后端无缝接入 refine 前端框架。为什么选择 NestJSNode.js 是构建复杂、高级应用的流行运行时环境但当应用规模扩大时直接使用原生 Node.js 组织代码会变得难以维护。NestJS 正是在这一痛点下诞生的服务端框架它构建于 TypeScript 之上内置了可扩展、易维护的工程化结构并默认使用 Express 作为底层 HTTP 服务器同时也可以定制切换为 Fastify。NestJS 的核心优势体现在以下几个方面模块化架构代码按功能拆分为模块单个功能的所有代码只需通过导入 FeatureModule 即可整体复用。团队在小型或大型项目中都可以并行开发不同功能模块互不干扰。架构多样性原生支持单体Monolith与微服务Microservices两种架构并集成 GraphQL、CronJobs、WebSockets 等现代技术栈。内置校验体系提供开箱即用的验证系统在错误发生前执行校验规则降低出错概率。Angular 开发者友好如果你有 Angular 经验NestJS 几乎零学习曲线即可上手因为二者的依赖注入、装饰器与模块体系一脉相承。环境准备与项目初始化前置条件开始之前需要安装两样东西Node.js 环境npmNode 包管理器从 Node.js 官网下载安装包即可一次性获得上述两者。安装完成后可在命令行中执行node -v与npm -v确认版本号正常输出。安装 Nest CLI打开终端依次执行以下命令# 创建一个目录存放项目示例目录名 nestjs-demo mkdir nestjs-demo cd nestjs-demo # 全局安装 Nest CLI npm i -g nestjs/cli # 验证安装此时应输出 nest 命令的帮助信息 nest创建项目使用 Nest CLI 在当前目录创建名为auto-garage-nest的项目nest new auto-garage-nest注意交互式提示中选择npm作为包管理器。命令执行完成后项目内会自动生成一套标准的 NestJS 目录结构其中包括src/main.ts应用入口、src/app.module.ts根模块、src/app.controller.ts、src/app.service.ts以及tsconfig.json、package.json等工程化配置。NestJS 三大核心组件在进入实战之前先理解 NestJS 应用由哪三类组件构成Modules模块模块用于对服务Service、控制器Controller或其他组件进行分组。一个模块可以把整个功能的实现封装在内例如独立的认证模块、日志模块等。所有代码只需导入 FeatureModule 即可整体可用。Controllers控制器控制器是应用的入口点。它接收特定的 HTTP 请求并将响应返回给客户端。每个控制器与不同的路由及其 HTTP 方法GET、POST、PUT、DELETE相关联负责请求的分发与响应。Providers提供器/服务提供器常被称为服务承载业务逻辑代码在此处与数据库交互、处理数据或调用外部 API。一个提供器可以创建包含业务逻辑的服务实例并在任意其他组件中复用这正是 NestJS 依赖注入机制的体现。实战构建 auto-garage-nest 车辆管理应用下面我们按照六步把上述三大组件组合成一个可运行的车辆管理 CRUD 应用。先进入项目目录cd auto-garage-nestStep 1创建 Module项目初始化时会自动生成根模块app.module.ts它是包含所有模块引用关系的根模块。为了有效组织代码我们创建一个vehicles模块专门管理自动车库的车辆功能nest generate module vehicles该命令会在src/vehicles目录下生成vehicles.module.ts并自动更新app.module.ts将其导入。此时vehicles.module.ts的内容如下import { Module } from nestjs/common; Module({}) export class VehiclesModule {}Step 2用 Controller 定义端点接下来创建一个容器定义车辆管理的端点。运行nest generate controller vehicles命令会自动在src/vehicles目录下创建vehicles.controller.ts。我们在其中定义GET、POST、PUT、DELETE五类端点列表、单条查询、创建、更新、删除并注入VehiclesServiceimport { Controller, Get, Post, Put, Delete, Body, Param, } from nestjs/common; import { VehiclesService } from ./vehicles.service; import { Vehicle } from ./entities/vehicle.entity; Controller(vehicles) export class VehiclesController { constructor(private readonly vehiclesService: VehiclesService) {} Get() async findAll(): PromiseVehicle[] { return this.vehiclesService.findAll(); } Get(:id) async findOne(Param(id) id: string): PromiseVehicle { return this.vehiclesService.findOne(id); } Post() async create(Body() vehicle: Vehicle): PromiseVehicle { return this.vehiclesService.create(vehicle); } Put(:id) async update( Param(id) id: string, Body() vehicle: Vehicle, ): PromiseVehicle { return this.vehiclesService.update(id, vehicle); } Delete(:id) async remove(Param(id) id: string): Promisevoid { return this.vehiclesService.remove(id); } }这里Controller(vehicles)将路由前缀绑定为/vehiclesParam(id)通过id将字符串参数显式转换为数字供后续服务层使用。Step 3创建 Entity为了在数据库中建立结构并与数据库交互需要创建实体。在src/vehicles目录下新建entities目录并在其中创建vehicle.entity.tsimport { Entity, PrimaryGeneratedColumn, Column } from typeorm; Entity() export class Vehicle { PrimaryGeneratedColumn() id: number; Column() make: string; Column() model: string; Column() year: number; Column() color: string; }我们使用TypeORM包把实体转换为数据库表Entity()声明表结构PrimaryGeneratedColumn()声明自增主键Column()声明普通字段。注意如果typeorm包报错请先安装npm install typeorm。为了使用 SQLite 数据库配合 TypeORM安装以下包npm install nestjs/typeorm typeorm sqlite3安装完成后在项目根目录创建ormconfig.json并添加如下配置{ type: sqlite, database: garage.sqlite, entities: [dist/**/*.entity.js], synchronize: true }配置项说明type数据库类型这里为sqlitedatabase数据库文件名应用运行后会在本地生成garage.sqlite文件entities实体文件扫描路径指向编译产物dist目录下的.entity.js文件synchronize设为true时应用启动会自动依据实体同步建表仅适合开发环境生产环境应改用 migration。Step 4用 Service 封装业务逻辑创建服务层把直接与数据库交互的业务逻辑放入其中。在src/vehicles目录下新建vehicles.service.ts包含以下五类逻辑查询所有车辆findAll查询指定车辆findOne创建车辆create更新车辆信息update删除车辆removeimport { Injectable } from nestjs/common; import { InjectRepository } from nestjs/typeorm; import { Repository, FindOneOptions } from typeorm; // Import FindOneOptions import { Vehicle } from ./entities/vehicle.entity; Injectable() export class VehiclesService { constructor( InjectRepository(Vehicle) private vehicleRepository: RepositoryVehicle, ) {} async findAll(): PromiseVehicle[] { return this.vehicleRepository.find(); } async findOne(id: number): PromiseVehicle { const options: FindOneOptionsVehicle { where: { id } }; // Construct FindOneOptions return this.vehicleRepository.findOne(options); } async create(vehicle: Vehicle): PromiseVehicle { return this.vehicleRepository.save(vehicle); } async update(id: number, vehicle: Vehicle): PromiseVehicle { await this.vehicleRepository.update(id, vehicle); const options: FindOneOptionsVehicle { where: { id } }; return this.vehicleRepository.findOne(options); } async remove(id: number): Promisevoid { await this.vehicleRepository.delete(id); } }这里通过InjectRepository(Vehicle)注入 TypeORM 为Vehicle实体生成的 RepositoryInjectable()使该类可被 Nest 依赖注入容器管理。findOne与update中使用FindOneOptions显式构造where: { id }查询条件这是 TypeORM 较新版本的推荐写法。注意如果nestjs/typeorm导入报错说明缺少该 NestJS 专用模块它为在 NestJS 应用中使用 TypeORM 提供集成工具执行npm install nestjs/typeorm修复。Step 5组装模块并配置 TypeORM最后一步把车辆功能的全部组件放进模块中。控制器因为是命令行生成已被自动添加我们补充 TypeORM、实体与服务的注册vehicles.module.ts内容如下import { Module } from nestjs/common; import { TypeOrmModule } from nestjs/typeorm; import { Vehicle } from ./entities/vehicle.entity; import { VehiclesController } from ./vehicles.controller; import { VehiclesService } from ./vehicles.service; Module({ imports: [TypeOrmModule.forFeature([Vehicle])], controllers: [VehiclesController], providers: [VehiclesService], }) export class VehiclesModule {}其中TypeOrmModule.forFeature([Vehicle])用于在当前模块范围内注册实体对应的 Repository使其可以被注入到 Service 中。接着在app.module.ts中添加TypeOrmModule.forRoot()以集成 TypeORM 并建立数据库连接import { Module } from nestjs/common; import { AppController } from ./app.controller; import { AppService } from ./app.service; import { VehiclesModule } from ./vehicles/vehicles.module; import { TypeOrmModule } from nestjs/typeorm; import { Vehicle } from ./vehicles/entities/vehicle.entity; Module({ imports: [ TypeOrmModule.forRoot({ type: sqlite, database: garage.sqlite, entities: [Vehicle], synchronize: true, }), VehiclesModule, ], controllers: [AppController], providers: [AppService], }) export class AppModule {}TypeOrmModule.forRoot()与 Step 3 中ormconfig.json是两种等价的配置方式前者把配置写在代码里并可显式列出实体类后者由 TypeORM 从配置文件读取。二者选其一即可示例项目采用代码内配置方式。Step 6运行与测试 CRUD 接口所有组件就绪后启动开发服务器npm run start:dev应用将运行在 http://localhost:3000/。此时可以用 Postman 等工具对已实现的 CRUD 接口发起 HTTP 调用验证POST /vehicles携带{ make: Toyota, model: Corolla, year: 2022, color: red }JSON 请求体创建车辆GET /vehicles获取已插入的全部车辆列表GET /vehicles/:id按主键查询单条车辆PUT /vehicles/:id按主键更新车辆字段DELETE /vehicles/:id按主键删除车辆。延伸refine 对 NestJS 的官方支持作为额外的福利refine 对 NestJS 生态提供了完备的官方支持——具体表现为两个开箱即用的数据提供器data provider包均已在当前仓库中维护见 packages/nestjsx-crud/README.md 与 packages/nestjs-query/README.md。NestJS CRUD 数据提供器NestJS CRUD 是帮助开发者快速创建 RESTful CRUD API 的模块。refine 的refinedev/nestjsx-crud数据提供器可让你把基于 NestJS CRUD 实现的 API 直接连接到 refine高效管理数据。安装与基本用法如下npm install refinedev/nestjsx-crudimport dataProvider from refinedev/nestjsx-crud; const App () { return ( Refine dataProvider{dataProvider(API_URL)} /* ... */ {/* ... */} /Refine ); };从源码结构看packages/nestjsx-crud/src/provider.ts该提供器内部使用nestjsx/crud-request的RequestQueryBuilder构建查询字符串getList会依次调用handleFilter、handleJoin、handlePagination、handleSort等工具把 refine 的筛选、关联查询meta?.join、分页与排序参数翻译为 NestJS CRUD 约定的查询语法update使用PATCH方法createMany走/bulk端点deleteMany则并发调用各资源的DELETE接口并统一通过transformHttpError将 axios 错误转换为 refine 的HttpError结构。NestJS Query 数据提供器对于使用 GraphQL 的后端refine 还提供了refinedev/nestjs-query数据提供器。它基于 NestJS Query 规范借助 Node.js 驱动的 GraphQL TypeScript可以构建更高效、更独立的 API 并轻松接入 refine。安装与用法如下npm install refinedev/nestjs-query graphql-tag graphql-wsimport dataProvider, { GraphQLClient, liveProvider, } from refinedev/nestjs-query; import { createClient } from graphql-ws; const App () { return ( Refine dataProvider{dataProvider(new GraphQLClient(API_URL))} liveProvider{liveProvider(createClient({ url: WS_URL }))} /* ... */ {/* ... */} /Refine ); };从源码看packages/nestjs-query/src/dataProvider/index.ts该提供器使用gql-query-builder按需生成查询getList默认查询nodes与totalCount字段并把筛选、排序、分页映射为xxxFilter、xxxSort、OffsetPaging变量create、createMany、update等变更操作则生成createOneXxx、createManyXxx等 GraphQL mutation同时支持通过meta.gqlQuery/meta.gqlMutation传入自定义查询片段。更值得一提的是 packages/nestjs-query/src/liveProvider/index.ts 中的liveProvider它基于graphql-ws建立 WebSocket 连接为useList订阅created、updated、deleted三种变更事件为useOne订阅updated事件——这意味着当 NestJS Query 后端数据变化时refine 前端可以实时刷新无需手动轮询。结语本文完整走通了 NestJS 服务端应用的搭建全流程从理解为什么选择 NestJS、安装 CLI 与初始化项目到掌握 Module、Controller、Provider 三大核心组件再到用 TypeORM SQLite 逐步实现车辆的增删改查接口并运行测试。最后我们看到了 refine 对 NestJS 生态的官方支持——refinedev/nestjsx-crud与refinedev/nestjs-query两个数据提供器分别面向 REST 与 GraphQL 两种后端风格让你可以在 refine 前端中直接消费本文搭建的这类 NestJS 服务。虽然要构建企业级应用仍有大量 NestJS 知识需要学习但本文覆盖的基础概念已足够引领你走上正确的方向。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考