为了账号安全,请及时绑定邮箱和手机立即绑定

GraphQL 简易入门

为什么要使用GraphQL

GraphQL是由Facebook团队在2015年开源推出的一套用于替代传统的REST API的框架。利用它能够大幅提升开发效率以及应用性能。设想这样一个场景:

你想要获得一个用户的朋友的国家信息,如果你使用的是REST API的话,你可能需要同时调用以下这些接口:

  • /users/{userName}/friends: 返回类似 {id: 1, name: 'xxx', friends: [2,3,4] }的结构
  • /friends/{ID}: 返回类似{id: 2, name: 'xxx', country: 23}的结构
  • /countries/{ID}: 返回类似{id: 23, name: 'China', flag: 'xxx', language: 'Chinese'}的信息

先取回以scq000为用户名的朋友id,然后利用这些返回的用户id再查询详细的信息,最后再拼装成想要的数据结构。你会发现,随着应用复杂度的提升,API的数量以及请求的数量成倍地增加,客户端为了想要获得一个简单的数据信息,要往返多次地调用不同的API。

而GraphQL的出现就是为了解决上述这些问题的,它本质上是一门面向API的查询语言(Query Language for API)。可以根据客户端想要的数据,一次性地将数据取回来。

比如,上面的这个例子就能用下面的Graph 请求来描述:

{
    user {
        friend {
            name
            country
        }
    }
}

然后返回的数据是像这样:

{
    "user": {
        "friend": {
            "name": "scq000",
            "country": "China"
        }
    }
}

同时目前GraphQL也支持各种语言,对于主流的编程语言都有良好地支持,生态环境也搭建地不错。国外的大公司,如facebook, paypal, twitter, github等现在都在项目中大量使用GraphQL。

核心概念

GraphQL中一个核心的概念就是Schema, 它是客户端和服务端之间进行沟通的协议,定义好对应的数据schema后,前后端就可以独立地进行开发,从而提高效率。

一个schema是由query和mutation两部分组成的,如:

schema {
    query: Query,
    mutation: Mutation
}

其中, query对应的就是请求数据的对象,而mutation主要负责进行副作用,如create, delete, update等操作。

types

一个GraphQL schema中最基本的组件是对象类型,可以用来表示能从服务器获取什么类型的对象。GraphQL内置的标量数据类型(Scalar Types)有以下几种:

  • Int: a signed 32bit 带符号的32位整数

  • Float: 有符号双精度浮点型

  • String: UTF-8编码的字符串

  • Boolean: 布尔型,true和false两个值

  • ID: 唯一标识符,用以重新获取对象或作为缓存的键

还有枚举类型enum:

enum Country {
  CHINA
  JAPAN
  AMERICAN  
}

默认情况下每一个内置类型的都可以被设置成null,如果需要确保某个字段不为空,需要使用!符号:

type Author {
    id: ID!
    firstName: string,
    courses: [String]
}

注意到courses的类型是[String],这表示这个字段是个数组类型。

除了使用内置类型外,还可以自定义类型:

type Query {
    author_details: [Author]
}

type Mutation {
    addAuthor(firstName: String, lastName: sring): Author
}

Queries

Fields

字段是Query对象上最基本的组成单位,服务端和客户端的结构基本相同:

{
    viewer {
    	name
	}
}

Arguments

在GrahQL中,你可以给字段传递参数。这样可以避免重复的API请求,如下所示:

{
    followers (last: 3) {
        nodes {
            id
        }
    }
}

这表示请求最后3个记录,你还可以使用:

{
    author (id: "1000") {
        name
        age
    }
}

这表示请求id为1000的记录。

Alias

由于在请求中不能使用不同的参数来请求相同的字段,因此就需要使用alias来给字段起别名:

{
    firstFollowers: followers (first: 3) {
        nodes {
    		id
    		name
		}
    	
    }
	lastFollowers: followers (last: 3) {
        nodes {
        	id
        	name
    	}
    }
}

Fragments

片段(Fragment)是可复用的单位,可以让你在多个Query对象中利用同一个Fragments:

{
    nodes {
    	...userInfo
	}
}

fragment userInfo on User {
    id
    bio
}

fragment关键字声明一个片段对象,然后再使用的时候直接利用扩展运算符...就可以了。

Operation name

我们一般在声明查询对象的时候都是用简写形式省略query关键字和查询名称,不过如果需要减少代码歧义,则需要显式声明:

query ViewerInfo {
    viewer {
    	name
    	date
	}
}

Variables

字段的参数可以是动态的,所以使用变量进行控制:

query ViewerInfo($isOwner: Boolean!) {
    viewer {
    	id
    	name
    	start(ownedBy)
	}
}
{
    isOwner: false
}

Mutations

用来更新数据的(create, update, delete)的副作用。

Query的时候所有的查询是同时执行的,但是Mutation操作是按顺序执行的:

mutation NewStatus($input: ChangeUserStatusINput!) {
    changeUserStatus(input: $input) {
        clientMutationId
        status {
            message
        }
    }
}

生态以及工具

整个GraphQL架构是有客户端和服务端两部分组成中,其中客户端主要负责处理数据请求的状态管理,缓存,分页,错误处理以及schema的校验等工作。而服务端主要和数据库打交道, 有schema 和resolvers, resolver主要处理业务逻辑。

现在比较主流的GraphQL客户端框架有Apollo ClientRelay

服务端可以使用Apollo Server, express graphql, graphql yoda等。

数据库方面可以使用Prisma, 是替代传统的ORM框架的方案,支持多种数据库。

最后再推荐一些其他有用的工具:

graphql voyager: 图示,模型设计的工具

graphql faker: mock 数据

graphql visual editor: 可视化编辑器

如何使用

最后,我们来写一个实际的demo来应用一下GraphQL:

首先我们要先来定义一下schema对象:

import {
    GraphQLSchema,
    GraphQLObjectType,
    GraphQLInt
} from "graphql";

let counter = 1;

let schema = new GraphQLSchema({
    query: new GraphQLObjectType({
        name: 'Query',
        fields: () => ({
            counter: {
                type: GraphQLInt,
                resolve: () => counter
            }
        })
    }),
    mutation: new GraphQLObjectType({
        name: "Mutation",
        fields: () => ({
            incrementCounter: {
                type: GraphQLInt,
                resolve: () => ++counter
            }
        })
    })
})

这里定义了一个counter的字段,然后mutation里有一个incrementCounter的方法,每次执行这个mutation,都会让counter的值加1。

有了schema后,接着就可以利用express来开启一个叫做/graphql的接口,并使用已经定义好的schema:

const app = express();
const port = 3000

app.use('/graphql', GraphQLHTTP({
    schema
}));

app.listen(port, () => console.log(`Example app listening on port ${port}`))

最后我们就可以直接在浏览器中输入localhost:3000/graphql使用了

参考资料

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
14
获赞与收藏
130

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消