这次我们通过快速搭建一个 GraphQL 项目来学习如何使用它。
项目使用的技术栈:
- Typescript - JavaScript 的类型化超集,可编译为纯 JavaScript。
- Node.js - 一个基于 Chrome V8 引擎 的 JavaScript 运行时。
- GraphQL - API 的查询语言,用于使用现有数据来完成这些查询的运行时。
- TypeGraphQL - Node.js 中 GraphQL API 的现代框架。
项目依赖
项目初始化
- 终端前往存放项目的文件夹,创建项目:
$ mkdir tinylearn && cd tinylearn
- 项目初始化:
$ npm init -y
- 用编辑器打开项目(笔者使用的是 VSCode):
- 安装依赖包,终端输入:
$ npm install apollo-server@2.13.1 \
class-validator@0.12.2 \
graphql@14.6.0 \
reflect-metadata@0.1.13 \
type-graphql@0.17.6
$ npm install --save-dev @types/graphql@14.0.7 \
@types/node@12.12.39 \
ts-node@8.10.1 \
typescript@3.9.2
- 在项目根目录加入文件
tinylearn/tsconfig.json
:
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"lib": [
"es2018",
"esnext.asynciterable"
],
"strictFunctionTypes": true,
"strictNullChecks": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
tsconfig.json 是 Typescript 的配置文件,它指定编译项目所需的根文件和编译器选项。
Hello world
准备工作已经做完了,接下来我们写点代码。
- 创建
tinylearn/src/index.ts
文件,并写入相关代码:
index.ts:
console.log('Hello world!');
- 修改
package.json
:
{
"name": "tinylearn",
...
"scripts": {
+ "start": "ts-node src"
- "test": "echo \"Error: no test specified\" && exit 1"
},
...
}
- 运行以下命令,启动项目:
$ npm start
结果如下:
恭喜 Hello world 跑起来了!
引入 GraphQL
接下来我们要写一些逻辑了。
- 修改
src/index.ts
为:
import "reflect-metadata"
import { buildSchema, ObjectType, Field, ID, Resolver, Query } from "type-graphql";
import { ApolloServer } from "apollo-server";
@ObjectType()
class Post {
@Field(type => ID)
id: string;
@Field()
created: Date;
@Field()
content: string;
}
@Resolver(Post)
class PostResolver {
@Query(returns => [Post])
async posts(): Promise<Post[]> {
return [
{
id: "0",
created: new Date(),
content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
},
{
id: "1",
created: new Date(),
content: '为什么GraphQL是API的未来'
},
{
id: "2",
created: new Date(),
content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
},
]
}
}
async function main() {
try {
const schema = await buildSchema({
resolvers: [PostResolver],
dateScalarMode: 'timestamp'
});
const server = new ApolloServer({
schema,
playground: true
});
const { url } = await server.listen(4444);
console.log(`GraphQL Playground available at ${url}`);
} catch (error) {
console.error(error);
}
}
main();
- 再次运行项目:
$ npm start
结果:
玩一玩
浏览器访问网址 http://localhost:4444/:
我们先点击右侧 SCHEMA
按钮:
然后在左侧输入:
它会有自动补全,所以输入应该会很轻松。
点击中间圆形的播放按钮:
其实这个页面就像是 Postman,左边可以看作是前端发请求的配置,中间是服务器返回的 json,右边可以看作是后端的 API 文档。
我们改变参数再发请求试试:
整个过程就像是后端定义了一个 json graph(也就是 schema),前端根据需求拉取这个 graph 的部分数据。
我们再来回顾一下代码 tinylearn/src/index.ts
:
@ObjectType()
class Post {
@Field(type => ID)
id: string;
@Field()
created: Date;
@Field()
content: string;
}
@Resolver(Post)
class PostResolver {
@Query(returns => [Post])
async posts(): Promise<Post[]> {
return [
{
id: "0",
created: new Date(),
content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
},
{
id: "1",
created: new Date(),
content: '为什么GraphQL是API的未来'
},
{
id: "2",
created: new Date(),
content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
},
]
}
}
后端定义 Schema:
前端根据需求,参考 Schema 后发起请求:
前端获取返回值:
另外,这个 json graph (schema) 是一个严格的类型系统:
-
posts: [Posts!]!
- Post 数组 -
id: ID!
- 字符串 ID -
created: Timestamp!
- 时间戳 -
content: String!
- 字符串
我们检查一下返回值的类型:
确实如此,返回值的类型和 Schema 里面一样:
posts
是 Post
数组。
id
是字符串 ID。
created
是时间戳。
content
是字符串。
大家对 GraphQL 是否有了新的认识?欢迎给我留言。
未完待续
大家可能还是有很多疑问,不用心急,我们慢慢来。
下一篇 《Flutter 如何接入 GraphQL》 会介绍如何使用 Flutter(移动端大热) 接入本章写好的接口。让前端真正的跑起来,这样我们就会对 GraphQL 有更完整的认知。
Flutter Demo:
源码
代码地址
tinylearn/src/index.ts:
import "reflect-metadata"
import { buildSchema, ObjectType, Field, ID, Resolver, Query } from "type-graphql";
import { ApolloServer } from "apollo-server";
@ObjectType()
class Post {
@Field(type => ID)
id: string;
@Field()
created: Date;
@Field()
content: string;
}
@Resolver(Post)
class PostResolver {
@Query(returns => [Post])
async posts(): Promise<Post[]> {
return [
{
id: "0",
created: new Date(),
content: '提供基于GraphQL API的数据查询及访问,「Hasura」获990万美元A轮...'
},
{
id: "1",
created: new Date(),
content: '为什么GraphQL是API的未来'
},
{
id: "2",
created: new Date(),
content: 'Netflix:我们为什么要将 GraphQL 引入前端架构?'
},
]
}
}
async function main() {
try {
const schema = await buildSchema({
resolvers: [PostResolver],
dateScalarMode: 'timestamp'
});
const server = new ApolloServer({
schema,
playground: true
});
const { url } = await server.listen(4444);
console.log(`GraphQL Playground available at ${url}`);
} catch (error) {
console.error(error);
}
}
main();