NestJS + MongoDB + TypeORM + Apollo-graphQL

The first step is project construction

  1. Install @nest/ CLI scaffolding for generating projects;

npm i -g @nest/cli
Copy the code
  1. Generating project

nest new nest-typeorm-graphql
cd ./nest-typeorm-graphql
Copy the code
  1. Start the project

yarn start:dev
Copy the code

After the startup is complete, the default address is http://localhost:3000/, and you should see the familiar Hello World! ;


Step 2: Connect to the MongoDB database

TypeORM is used as database entity mapping tool, which can greatly simplify database connection and CRUD operation.

  • TypeORM Official Introduction and documentation: TypeORM document (Chinese can be changed in the upper right corner)
  • Guide to using TypeORM under the NestJS framework: @nestjs/ TypeORM documentation
  1. Install dependencies

yarn add @nestjs/typeorm typeorm mongodb
Copy the code
  1. insrc/app.module.tsTo configure database connection:

    . .import { join } from 'path';
        import { TypeOrmModule } from '@nestjs/typeorm';
    
        @Module({
          imports: [
            TypeOrmModule.forRoot({
              type: 'mongodb',
              host: 'localhost',
              port: 27017,
              database: 'typeorm'.// Database name
              entities: [join(__dirname, '**/entity/*.{ts,js}')].// File path matching that requires automatic entity mapping
              useNewUrlParser: true.// Use the new mongo connection Url parsing format
              synchronize: true.// Automatically synchronize the database to generate entity})].Copy the code
    • We need to create an empty database in MongoDB ahead of timetypeorm;
    • In the TypeOrmModule configuration above we set the file path for database entity mapping to**/entity/*.{ts,js};
    • For ease of development, setsynchronize: trueTo enable TypeOrM to automatically generate entity class definitions in MongoDBCollections, which saves us from having to set up Collections manually;

Step 3, GraphQL configuration

  1. Install dependencies

yarn add @nestjs/graphql graphql-tools graphql apollo-server-express
Copy the code
  1. insrc/app.module.tsConfigure GraphQL in:

There are two strategies to develop GraphQL in NestJS framework. One is to write entity class definition in Code First mode, and the other is to write Schema. GQL in schema First mode. In order to keep the development style and thinking consistent, the code first strategy is adopted here;

. .import { GraphQLModule } from '@nestjs/graphql';

    @Module({
      imports: [
        GraphQLModule.forRoot({
          autoSchemaFile: './schema.gql'.// write entity definitions first})],})Copy the code

The fourth step is to develop business modules

For quick development, @nest/ CLI command line tool is used to generate the code here. The first step has been installed globally.

We develop a Goods management module as an example:

  1. generategoods.module.ts.ModuleFile;

    nest generate module goods
    Copy the code
    I can write it as thetanest g mo goods

    The database entity class definition is introduced here, otherwise the following services will not get the database Repository object:

       import { TypeOrmModule } from '@nestjs/typeorm'
       import { Goods } from './entity/goods.entity'
       
       @Module({ imports: [TypeOrmModule.forFeature([Goods])], ... . })Copy the code
  2. generategoods.service.tsIs used to implement the specific database operations of resolver’s @Query and other GraphQL methods;

    nest generate service goods
    Copy the code

    We need to implement CRUD methods in GoodsService:

    The use of this.goodsRepository can be found in the official TypeORM Repository documentation

    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)
      }
    }
    Copy the code
  3. generategoods.resolver.ts, used to implement Query and Mutation of GraphQL;

    nest generate resolver goods
    Copy the code

    Query and Mutations define GraphQL in GoodsResolver:

    Refer to NestJS Resolvers document and NestJS Mutations document for specific use;

     import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
     import { GoodsService } from './goods.service';
     import { GoodsTypeGraphql, GoodsInputTypeGraphql, GoodsInsertTypeGraphql } from './entity/goods.type-graphql';
     
     // Wrap the Promise return to make async/await easier to write in synchronous syntax
     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 all items @Query(() => [GoodsTypeGraphql])
       async getAllGoods(a) {
         return this.goodsService.findAll(a); } // Query a single item @Query(() => GoodsTypeGraphql)
       async getGoods(@Args('id') id: string) {
         return this.goodsService.findOneById(id); } // Add a new item @Mutation(() => GoodsTypeGraphql)
       async addOneGoods(@Args('goods') goods: GoodsInsertTypeGraphql) {
         return this.goodsService.addOne({ ...goods }); } // Update a commodity information @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); } // Delete a product info @Mutation(() = >Boolean)
       async deleteOneGoods(@Args('id') id: string) {
         const [err] = await awaitWrap(this.goodsService.deleteOne(id));
         if (err) {
           return false;
         }
         return true; }}Copy the code
  4. generategoods.entity.ts, used to define TypeOrmDatabase entity classDefinition;

    See the NestJS Database for detailed documentation

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

    The entity class is defined as follows:

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

    After the service is started, a Collections with the corresponding name is automatically generated under MongoDB’s Typeorm library

  5. generategoods.type-graphql.ts, GraphQL type definition file;

    The code-first strategy is used to write the GraphQL type definition class. @nestjs/ GraphQL will automatically generate schema.gQL;

    nest generate class goods.type-graphql --no-spec
    Copy the code

    Define the GraphQL type:

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

    In order to reduce the repetitive code and write @field, we used the CLI plug-in of @nestjs/ GraphQL

    Change the nest-cli.json file in the root directory to:

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

    The final result is the following files:


    You’re done. Start the service again

    yarn start:dev
    Copy the code

    Waiting for start to finish to visit http://localhost:3000/graphql, open GraphQL Playground happy play:

    Github Address:Github.com/wenqieqiu/n…

    Next time notice –Front-end Vue + TS + Apollo-graphQL easy to add, delete, change and check