阅读 677
nest.js和graphql的亲密结合(一)——服务端

nest.js和graphql的亲密结合(一)——服务端

代码仓库

在开发完公司项目后,发现项目后端逻辑单一,对比前后端分离的开发流程,决定使用nestjs+graphql+mysql对前后端分离的项目进行优化,优化开发资源。

为什么使用nestjs

Nest 是一个用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)并结合了 OOP(面向对象编程),FP(函数式编程)和 FRP(函数式响应编程)的元素。

在底层,Nest使用强大的 HTTP Server 框架,如 Express(默认)和 Fastify。Nest 在这些框架之上提供了一定程度的抽象,同时也将其 API 直接暴露给开发人员。这样可以轻松使用每个平台的无数第三方模块。

为什么使用graphql

  • 避免对数据的过度抓取
  • 兼容不同环境对数据需求
  • 产品的快速迭代

简介

1. 什么是nest.js

用于构建高效且可伸缩的服务端应用程序的渐进式 Node.js 框架。 完美支持 Typescript,面向 AOP 编程,支持 typeorm,Node.js 版的 spring,构建微服务应用。

2. 什么是graphql

GraphQL 是一种用于应用编程接口(API)的查询语言和服务器端运行时,可以使客户端准确地获得所需的数据,没有任何冗余。

nest.js项目搭建

1. 安装Nest CLI
npm i -g @nestjs/cli // 安装nest-cli
nest new nest-graphql // 新建工程
cd nest-grapql
yarn run start
复制代码
2.添加@nestjs/graphql

npm i --save @nestjs/graphql graphql-tools graphql apollo-server-express ts-morph @apollo/gateway

3.引入GraphQLModule
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';

@Module({  
    imports: [GraphQLModule.forRoot({})],  
    controllers: [AppController],  
    providers: [AppService],
})
export class AppModule {}
复制代码

此时运行npm start会抛出无法找到存在schema的异常,这里只需要配置对应的gql文件就可以解决。

1625888504945.jpg

4.添加@nestjs/config

在项目开发的过程中,我们经常会遇到不同项目,或者在不同环境下需要配置不同的参数。又或者,我们在开发的不同环境下都需要有修改不通的参数。在这种情况下,我们一般使用dotenv读取项目根目录下的.env文件,并通过process访问参数。而在nestjs中,我们使用@nestjs/config包中的ConfigModule来进行参数的处理。

npm i --save @nestjs/config 添加对应配置文件

// src/config/configuration.ts
export default () => ({  
    graphql: {    
        installSubscriptionHandlers: true, // 启用订阅    
        typePaths: ['./**/*.graphql'], // 指示 GraphQLModule 应该查找 GraphQL 文件的位置
    },
});
复制代码

在AppMoudle中注入模块,并导入到GraphQLModule

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ConfigModule, ConfigService } from '@nestjs/config';
import config from './config/configuration';

@Module({  
imports: [    
    ConfigModule.forRoot({
        envFilePath: '.env',//      
        ignoreEnvFile: false,      
        isGlobal: true,      
        load: [config],    
    }),    
    GraphQLModule.forRootAsync({      
        imports: [ConfigModule],      
        useFactory: async (configService: ConfigService) => {        
            return {          
                typePaths: configService.get('graphql.typePaths'),        
            };      
        },      
        inject: [ConfigService],    
    }),  
],  
controllers: [AppController],  
providers: [AppService],
})
export class AppModule {}
复制代码
  1. 注入对应的业务模块
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { CatsModule } from './cats/cats.module';
import config from './config/configuration';

@Module({
  imports: [
    CatsModule,
    ConfigModule.forRoot({
      envFilePath: '.env',
      ignoreEnvFile: false,
      isGlobal: true,
      load: [config],
    }),
    GraphQLModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => {
        return {
          typePaths: configService.get('graphql.typePaths'),
        };
      },
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService], 
}) 
export class AppModule {} 
复制代码

为什么导入模块有的模块后面加forRoot

在nest.js中,我们会注意到在imports的数组中,对应的模块会调用forRoot()方法,并可以传入一个可选的参数家对象,那么这forRoot()是什么呢?

在nestjs中,注册模块不仅可以使用imports:[ConfigModule],也可以使用代码去动态注册,也就是调用模块类上的静态方法forRoot,返回一个对象,且这个对象需要是DynamicModule实例。

// 这几个属性和我们在使用@module时使用的属性是一致的
{
      module: ConfigModule,
      providers: [ConfigService],
      exports: [ConfigService],
}
// 当我们调用forRoot()返回动态模块,动态模块将会被注册
复制代码

而传入的options对象可以作为内容提供者provider注册到动态模块中使用,进而起到了配置模块的作用

import { DynamicModule, Module } from '@nestjs/common';

import { ConfigService } from './config.service';

@Module({})
export class ConfigModule {
  static forRoot(options): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        {
          provide: 'CONFIG_OPTIONS', // 可以使用@Inject('CONFIG_OPTIONS') 在需要的模块中注入
          useValue: options, // options使用了自定义提供者的方法去注入
        },
        ConfigService,
      ],
      exports: [ConfigService],
    };
  }
}

复制代码
import { Injectable, Inject } from '@nestjs/common';

import * as dotenv from 'dotenv';
import * as fs from 'fs';

import { EnvConfig } from './interfaces';

@Injectable()
export class ConfigService {
  private readonly envConfig: EnvConfig;

  constructor(@Inject('CONFIG_OPTIONS') private options) { // 这里使用了@Inject 标识了对象
    const filePath = `${process.env.NODE_ENV || 'development'}.env`;
    const envFile = path.resolve(__dirname, '../../', options.folder, filePath);
    this.envConfig = dotenv.parse(fs.readFileSync(envFile));
  }

  get(key: string): string {
    return this.envConfig[key];
  }
}

复制代码

至此,Nest.js的结合graphql整体框架。都已完成。后续将会第二篇讲详细说明客户端的搭建。

文章汇总

文章分类
前端
文章标签