Node GraphQL TS

在上一章节中主要说明了如何使用Node的GraphQL来编排我们的接口,因为现在TS的爆火,大部分工具类都已变更为TS为主要的开发语言。因此这篇讲说明如何使用TypeGraphQL来实现,并且引入Apollo Server。

Apollo Server是什么

Apollo Server是一款开源的、符合规格的GraphQL服务,与包括Apollo Client在内的任何GraphQL客户端兼容。这是构建生产就绪、自我记录的GraphQL API的最佳方式,该API可以使用来自任何来源的数据。它的运行模式如图

Apollo Server

作用
  • 独立的GraphQL服务,包括在无服务环境中
  • 应用程序现有Node.js中间件(如Express或Koa)的附加组件
  • 联合图(federation)的网关
能力
  • 简单的设置,因此您的客户端开发人员可以快速开始获取数据
  • 渐进式采用,允许您根据需要添加功能
  • 与任何数据源、任何构建工具和任何GraphQL客户端的通用兼容性
  • 生产准备就绪,使您能够更快地发布功能

上手构建

在构建方式上与上一篇普通的Node GraphQL没有本质区别,首先安装依赖

npm install apollo-server-core apollo-server-koa  koa reflect-metadata type-graphql ts-node typescript --save

说明:因为改用了TS,所以这里安装了type-graphqlreflect-metadata 这个包的主要作用是在定义GaphQL时使用了修饰器,类似于Java等面向对象语言的注解@
在项目文件夹中创建index.ts并写入一下内容:

#index.ts
import {ApolloServer} from 'apollo-server-koa';
import {ApolloServerPluginDrainHttpServer} from 'apollo-server-core';
import {buildSchema} from "type-graphql";
// @ts-ignore
import Koa from 'koa';
// @ts-ignore
import {createServer} from 'http';
import {CategoryListResolver} from "./src/GraphQl";

const app = new Koa();
const httpServer = createServer();

async function startApolloServer() {
    const schema = await buildSchema({
        resolvers: [CategoryListResolver],
        emitSchemaFile: true
    });
    const server = new ApolloServer({
        schema,
        context: ({ ctx }) => ctx,
        plugins: [ApolloServerPluginDrainHttpServer({httpServer})],
    });
    await server.start();
    return server;
};

// @ts-ignore
startApolloServer().then(async server => {
    server.applyMiddleware({app});
    httpServer.on('request', app.callback());
    await new Promise(resolve => httpServer.listen({port: 4000}, resolve));
    console.log(` Server ready at http://localhost:4000${server.graphqlPath}`);
});

说明:在这个文件中我们会发现与普通的Node GraphQL不同就是多了一个叫buildSchema的函数,我们查看源码发现这里buildSchema(options: BuildSchemaOptions)多了BuildSchemaOptions参数和返回值变为Promise异步函数,与Node GraphQL相比也同样提供buildSchema,这个函数的本质是直接从源文档构建 GraphQLSchema ,从效率和成本上都是这个函数更值得使用,因此也会在项目目录生成gql文件。

创建Schema

src文件夹中创建Schema.ts,别写入一下内容:

import "reflect-metadata";
import {Field, ObjectType, InputType, Int} from 'type-graphql';

@ObjectType()
class SingleCategory {
    @Field() id: string
    @Field(() => String, {description: "级别", defaultValue: "无"})
    public level: string
    @Field() name: string
    @Field() parentId: string
    @Field(() => String, {description: "评价", defaultValue: "无"})
    public recommend: string
    @Field(() => [Int]) recs: number[]
}

@ObjectType()
class Extra {
    @Field() ct: string
}

@ObjectType()
class Page {
    @Field() totalCount: string
    @Field() pageSize: number
}

@ObjectType()
export class CategoryList {
    @Field() success: boolean
    @Field(() => [SingleCategory], {description: '数据集', defaultValue: []})
    public data!: SingleCategory[];
    @Field() extra: Extra
    @Field() page: Page
    @Field() resultCode: Number
}

//定义分类列表对象
@InputType()
// @ts-ignore
export class CategoryListInput implements Partial {
    @Field() platformId: string
    @Field() type: string
}

上述代码同样也以Category分类为例,这样看来使用了TS之后代码都要更清爽一些,看起来一目了然。在type-graphql中分别结构出了ObjectTypeFieldInputType等。

  • ObjectType对应GraphQLObjectType的对象类型定义
  • Field对应fields函数的每一项
  • InputType对应输入类型,在Node GraphQL写的参数加类型定义转换为修饰器加实现Partial接口,看着更简洁
    这个文件抛出两个CategoryListInputCategoryList分别代表输入的查询类和列表类,下一步在Resolver中使用。
创建Resolver

src文件夹下创建Resolver.ts,加入一下代码:

#src/Resolver.ts
import {Query, Resolver, Mutation, Arg, Ctx} from "type-graphql";
import {CategoryListInput, CategoryList} from "./Scheme";
import {categoryController} from "../controller/CategoryController";
import {ResolverResult} from "./Resolver";

@Resolver(of => CategoryList)
export class CategoryListResolver {
    // @ts-ignore
    @Query(returns => CategoryList)
    async getCategoryList(@Arg('CategoryListInput') {platformId, type}: CategoryListInput, @Ctx() ctx) {
        let {body} = await categoryController._lst(ctx, {platformId, type});
        let resolver = new ResolverResult(body);
        return resolver.toJson();
    }
}

在这里从type-graphql分别解构出QueryResolverMutationArgCtx。分别解释一下:

  • Resolver函数of => CategoryList 代表输出GraphQL的Schema实体,相当于type:CategoryList,async resolve(root, params, ctx) {return ...});
  • Query 代表Node GraphQL中的name: 'query', fields: () => ({ categoryList: categoryList }),写法上在这里做了进一步简化;
  • Arg 代表GraphQL的参数,相当于args: { platformId: { name: 'platformId', type: GraphQLString }, type: { name: 'type', type: GraphQLInt, } },这里做了进一步简化,将之前的参数定义变为@InputType()@Field修饰器加实现Partial接口的方式替换,在上面的Schema定义时已经介绍;
  • Ctx 上下文,这里指在index.ts中挂载KoaContext上下文,与Node GraphQL一致,只是又默认变为修饰器按需引入;
  • Mutation GraphQL的mutation,相当于new GraphQLSchema({ mutation: mutation })

从创建SchemaResolver到挂载都已经完成,下一步在package.json中添加一个启动命令。为了更好的调试,我们先增加nodemon包来监听src文件夹下的文件,有变更自动重启。执行以下命令:

npm install nodemon -D

package.json中增加

"scripts": {
    "dev": "nodemon --watch src -e ts --exec ts-node index.ts"
},

在项目文件夹下执行npm run dev之后访问浏览器http://127.0.0.1:4000/graphql。显示的界面如下:

Apollo Server

这里提供了两种方式,一种为图形界面的点击Query your server 会进入到apollo graphql stutio页面,这个页面是Apollo Server提供的;第二种为非图形界面就是下面用api接口请求的方式访问。在启动完成后,我们的项目路径下会产生schema.gql文件,内容如下:

#schema.gql
# -----------------------------------------------
# !!! THIS FILE WAS GENERATED BY TYPE-GRAPHQL !!!
# !!!   DO NOT MODIFY THIS FILE BY YOURSELF   !!!
# -----------------------------------------------

type CategoryList {
  """数据集"""
  data: [SingleCategory!]
  extra: Extra!
  page: Page!
  resultCode: Float!
  success: Boolean!
}

input CategoryListInput {
  platformId: String!
  type: Float!
}

type Extra {
  ct: String!
}

type Page {
  pageSize: Float!
  totalCount: String!
}

type Query {
  getCategoryList(CategoryListInput: CategoryListInput!): CategoryList!
}

type SingleCategory {
  id: String!

  """级别"""
  level: String
  name: String!
  parentId: String!

  """评价"""
  recommend: String
  recs: [Int!]!
}

内容其实就是将TSSchema转换为GraphQLSchema,或在apollo-server中都可以通过解构gql,直接编写GraphQL Schema,直接挂载到ApolloServer,例如:

const { ApolloServer, gql } = require('apollo-server');

// The GraphQL schema
const typeDefs = gql`
  type Query {
    "A simple type for getting started!"
    hello: String
  }
`;

// A map of functions which return data for the schema.
const resolvers = {
  Query: {
    hello: () => 'world',
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

回到我们的例子中,通过ApolloServer Studio访问结果如下图:


Apollo Server

接口文档在左侧,中间上半部分为GraphQL语句,中间下半部分为参数变量输入,右侧为查询结果,查询方式与Node GraphQL一致。


以上就是使用typegrapgql + ApolloServer + TS构建的GraphQL的全部内容。这里着重说一句ApolloServer并非免费,价格表在官网有说明

ApolloServer Price

你可能感兴趣的:(Node GraphQL TS)