Skip to content

wenqieqiu/nest-typeorm-graphql

Repository files navigation

启动步骤

# 安装依赖
pnpm i
# 开发模式运行
pnpm dev
# 生产模式运行
pnpm start:prod

技术栈 NestJS + MongoDB + TypeORM + Apollo-GraphQL

第一步,项目搭建

  1. 安装@nest/cli 脚手架用于生成项目;

pnpm i -g @nestjs/cli
  1. 生成项目

nest new nest-typeorm-graphql
cd ./nest-typeorm-graphql
  1. 启动项目

pnpm dev

启动完成后默认地址为:http://localhost:3000/,此时应该可以看到熟悉的Hello World!;


第二步,连接 MongoDB 数据库

这里使用了 TypeORM 作为数据库实体映射工具,可以大大简化数据库连接与 CRUD 操作;

  1. 安装依赖

    pnpm i -S @nestjs/typeorm typeorm mongodb
  2. src/app.module.ts里配置数据库连接:

        ... ...
        import { join } from 'path';
        import { TypeOrmModule } from '@nestjs/typeorm';
    
        @Module({
          imports: [
            TypeOrmModule.forRoot({
              type: 'mongodb',
              host: 'localhost',
              port: 27017,
              database: 'typeorm', // 数据库名
              entities: [join(__dirname, '**/entity/*.{ts,js}')], // 需要自动实体映射的文件路径匹配
              useNewUrlParser: true, // 使用新版mongo连接Url解析格式
              synchronize: true, // 自动同步数据库生成entity
            })
          ],
    • 在上面的 TypeOrmModule 配置里我们设置了数据库实体映射的文件路径为**/entity/*.{ts,js}
    • 为了开发方便,设置了synchronize: true,使 typeorm 可以自动在 MongoDB 里生成实体类定义的Collections,这样就省去了我们手动建立 Collections 的操作了;

第三步,GraphQL 配置

  1. 安装依赖

    pnpm i -S @nestjs/graphql graphql-tools graphql apollo-server-express
  2. src/app.module.ts里配置 GraphQL:

    在 NestJS 框架下有两种开发 GraphQL 的策略,一种是先写实体类定义 的代码先行Code First)方式,另一种是先 写schema.gql架构先行Schema First)方式;为了保持开发风格与思路一致 ,这里采用了代码先行的策略;

     import { GraphQLModule } from '@nestjs/graphql';
     import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
    @Module({
      imports: [
       GraphQLModule.forRoot<ApolloDriverConfig>({
           driver: ApolloDriver,
           autoSchemaFile: true, //代码先行(既先写实体定义)
        }),
      ],
    })

第四步,开发业务模块

为了快速开发,此处使用了@nest/cli 命令行工具生成代码,第一步里已经全局安装;

我们开发一个商品管理模块Goods作为示例:

  1. 生成 goods.module.ts, Module文件;

    nest generate module goods
    可以简写为 nest g mo goods

    这里要引入数据库实体类定义,否则下面的Service无法获取数据库Repository对象:

     import { TypeOrmModule } from '@nestjs/typeorm'
     import { Goods } from './entity/goods.entity'
    
     @Module({
       imports: [TypeOrmModule.forFeature([Goods])],
       ... ...
     })
  2. 生成 goods.service.ts, 用于实现 resolver 的 @Query 等 GraphQL 方法的具体数据库操作;

    nest generate service goods

    我们需要在GoodsService里需要实现 CRUD 方法:

    this.goodsRepository的使用方法可以参考 TypeORM 官方 Repository 文档

    import { Injectable } from '@nestjs/common';
    import { InjectRepository } from '@nestjs/typeorm';
    import { Repository } from 'typeorm';
    import { Goods } from './entity/goods.entity';
    
    @Injectable()
    export class GoodsService {
      constructor(@InjectRepository(Goods) public goodsRepository: Repository<Goods>) {}
    
      public findAll() {
        return this.goodsRepository.find();
      }
    
      public findOneById(id: string) {
        return this.goodsRepository.findOne(id);
      }
    
      public updateOne(goods: Partial<Goods>) {
        return this.goodsRepository.update(goods.id, goods);
      }
    
      public addOne(goods: Partial<Goods>) {
        return this.goodsRepository.save(goods);
      }
    
      public deleteOne(id: string) {
        return this.goodsRepository.delete(id);
      }
    }
  3. 生成 goods.resolver.ts, 用于实现 GraphQL 的 Query、Mutation;

    nest generate resolver goods

    GoodsResolver里定义 GraphQL 的 Query 与 Mutations:

    具体使用参考 NestJS Resolvers 文档与 NestJS Mutations 文档;

    import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
    import { GoodsService } from './goods.service';
    import { GoodsTypeGraphql, GoodsInputTypeGraphql, GoodsInsertTypeGraphql } from './entity/goods.type-graphql';
    
    // 包装Promise返回,使得async/await可以更方便写成同步语法的形式
    function awaitWrap<T, U = any>(promise: Promise<T>): Promise<[U | null, T | null]> {
      return promise.then<[null, T]>((data: T) => [null, data]).catch<[U, null]>(err => [err, null]);
    }
    
    @Resolver('Goods')
    export class GoodsResolver {
      constructor(private readonly goodsService: GoodsService) {}
    
      //查询所有商品
      @Query(() => [GoodsTypeGraphql])
      async getAllGoods() {
        return this.goodsService.findAll();
      }
    
      //查询单个商品
      @Query(() => GoodsTypeGraphql)
      async getGoods(@Args('id') id: string) {
        return this.goodsService.findOneById(id);
      }
    
      //新增一个商品
      @Mutation(() => GoodsTypeGraphql)
      async addOneGoods(@Args('goods') goods: GoodsInsertTypeGraphql) {
        return this.goodsService.addOne({ ...goods });
      }
    
      // 更新一个商品信息
      @Mutation(() => GoodsTypeGraphql)
      async updateGoods(@Args('goods') goods: GoodsInputTypeGraphql) {
        const [err] = await awaitWrap(this.goodsService.updateOne(goods));
        if (err) {
          return goods;
        }
        return this.goodsService.findOneById(goods.id);
      }
    
      // 删除一个商品信息
      @Mutation(() => Boolean)
      async deleteOneGoods(@Args('id') id: string) {
        const [err] = await awaitWrap(this.goodsService.deleteOne(id));
        if (err) {
          return false;
        }
        return true;
      }
    }
  4. 生成 goods.entity.ts, 用于定义 TypeOrm数据库实体类定义;

    具体文档可查看 NestJS Database

    cd ./src/goods
    mkdir entity
    cd ./entity
    nest generate class goods.entity --no-spec

    实体类定义如下:

    import { Entity, Column, ObjectID, ObjectIdColumn, PrimaryGeneratedColumn } from 'typeorm';
    
    @Entity()
    export class Goods {
      @PrimaryGeneratedColumn()
      @ObjectIdColumn()
      readonly id: ObjectID;
    
      @Column({ unique: true })
      readonly name: string;
    
      @Column()
      readonly price: number;
    
      @Column()
      readonly count: number;
    
      @Column()
      readonly remark: string;
    }

    启动服务后会自动在 MongoDB 的 typeorm 库下生成对应名称的 Collections

  5. 生成 goods.type-graphql.ts,GraphQL 的类型定义文件;

    这里使用了代码先行的策略,用于编写 GraphQL 类型定义类 ,@nestjs/graphql 将自动生成 schema.gql;

    nest generate class goods.type-graphql --no-spec

    最后定义 GraphQL 类型即可:

    import { ObjectType, Field, ID, InputType } from '@nestjs/graphql';
    
    @ObjectType()
    export class GoodsTypeGraphql {
      @Field(() => ID)
      readonly id: any;
      readonly name: string;
      readonly price?: number;
      readonly count?: number;
      readonly remark?: string;
    }
    
    @InputType()
    export class GoodsInsertTypeGraphql {
      readonly name: string;
      readonly price?: number;
      readonly count?: number;
      readonly remark?: string;
    }
    
    @InputType()
    export class GoodsInputTypeGraphql {
      @Field(() => ID)
      readonly id: any;
      readonly name: string;
      readonly price?: number;
      readonly count?: number;
      readonly remark?: string;
    }

    这里为了减少重复代码,少写@Field,我们使用了@nestjs/graphqlCLI 插件

    根目录下的nest-cli.json修改为:

    {
      "collection": "@nestjs/schematics",
      "sourceRoot": "src",
      "compilerOptions": {
        "plugins": [
          {
            "name": "@nestjs/graphql/plugin",
            "options": {
              "typeFileNameSuffix": [".type-graphql.ts"]
            }
          }
        ]
      }
    }

    最终得到如下若干文件: 文件列表.png


    大功告成,再次启动服务

    pnpm dev

    等待启动完成即可访问 http://localhost:3000/graphql,打开 GraphQL Playground 愉快玩耍了;

    下期预告 —— Vue + TypeScript + vue-apollo-graphql

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published