在上一章节中主要说明了如何使用Node的GraphQL来编排我们的接口,因为现在TS的爆火,大部分工具类都已变更为TS为主要的开发语言。因此这篇讲说明如何使用TypeGraphQL来实现,并且引入Apollo Server。
Apollo Server是什么
Apollo Server是一款开源的、符合规格的GraphQL服务,与包括Apollo Client在内的任何GraphQL客户端兼容。这是构建生产就绪、自我记录的GraphQL API的最佳方式,该API可以使用来自任何来源的数据。它的运行模式如图
作用
- 独立的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-graphql
,reflect-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
中分别结构出了ObjectType
、Field
、InputType
等。
-
ObjectType
对应GraphQLObjectType
的对象类型定义 -
Field
对应fields
函数的每一项 -
InputType
对应输入类型,在Node GraphQL写的参数加类型定义转换为修饰器加实现Partial
接口,看着更简洁
这个文件抛出两个类
,CategoryListInput
、CategoryList
分别代表输入的查询类和列表类,下一步在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
分别解构出Query
、 Resolver
、 Mutation
、 Arg
、Ctx
。分别解释一下:
-
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
中挂载Koa
的Context
上下文,与Node GraphQL一致,只是又默认变为修饰器按需引入; -
Mutation
GraphQL的mutation,相当于new GraphQLSchema({ mutation: mutation })
。
从创建Schema
、Resolver
到挂载都已经完成,下一步在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
。显示的界面如下:
这里提供了两种方式,一种为图形界面的点击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!]!
}
内容其实就是将TS
的Schema
转换为GraphQL
的Schema
,或在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访问结果如下图:
接口文档在左侧,中间上半部分为GraphQL语句,中间下半部分为参数变量输入,右侧为查询结果,查询方式与Node GraphQL一致。
以上就是使用typegrapgql + ApolloServer + TS
构建的GraphQL的全部内容。这里着重说一句ApolloServer
并非免费,价格表在官网有说明