Graphql入门
GraphQL是一个查询语言,由Facebook开发,用于替换RESTful API。服务端可以用任何的语言实现。具体的你可以查看Facebook关于GraphQL的文档和各种语言的实现
GraphQL的小历史
早在2012年,Facebook认为人们只有在离开PC的时候才会用智能手机,很快他们就发现这个认识是多么的错误!于是Facebook把注意力从Web移到了智能终端上。在那个时候,他们严重的依赖于RESTful API。大量的并发请求和对补充数据的二次请求给他们造成了很大的麻烦,尤其是响应时间。一个解决方案是设计足够多的资源来满足单次的请求。但是,这造成了服务端的扩展和维护困难。
在寻找更好的解决方案的过程中,Facebook的工程师发现开发人员不应该先入为主的把数据看成RESTful一样的集合。如何更好地存储和获取数据不应该是他们要主要考虑的内容。他们应该更多的考虑数据的关系,网状的关系。
在这个情况下GraphQL应运而生。
GraphQL工作机制
一个GraphQL查询可以包含一个或者多个操作(operation),类似于一个RESTful API。操作(operation)可以使两种类型:查询(Query)或者修改(mutation)。我们看一个例子:
query {
client(id: 1) {
id
name
}
}
你的第一印象:“这个不是JSON?”。还真不是!就如我们之前说的,GraphQL设计的中心是为客户端服务。GraphQL的设计者希望可以写一个和期待的返回数据schema差不多的查询。
注意上面的例子有三个不同的部分组成:
client
是查询的operation(id: 1)
包含了传入给Query的参数- 查询包含
id
和name
字段,这些字段也是我们希望查询可以返回的
我们看看server会给这个查询返回什么:
{
"data": {
"client": {
"id": "1",
"name": "Uncle Charlie"
}
}
}
就如我们期望的,server会返回一个JSON串。这个JSON的schema和查询的基本一致。
我们再看看另一个例子:
query {
products(product_category_id: 1, order: "price DESC") {
name
shell_size
manufacturer
price
}
}
这次我们查询products
,并传入两个参数:product_category_id
用于过滤,一个指明按照price
字段降序排列。查询中包含的字段是:name
、shell_size
、manufacturer
和price
)。
你可能已经猜到返回的结果是什么样子的了:
{
"data": {
"products": [
{
"name": "Mapex Black Panther Velvetone 5-pc Drum Shell Kit",
"shell_size": "22\"x18\" Bass Drum, 10\"x8\" & 12\"x9\" Toms, 14\"x14\" & 16\"x16\" Floor Toms",
"manufacturer": "Mapex",
"price": 2949.09
},
{
"name": "Pearl MCX Masters Natural Birdseye Maple 4pc Shell Pack with 22\" Kick",
"shell_size": "22x18\" Virgin Bass Drum 10x8\" Rack Tom 12x9\" Rack Tom 16x16\" Floor Tom",
"manufacturer": "Pearl",
"price": 1768.33
}
]
}
}
从这几个初级的例子里你可以看出来GraphQL允许客户端明确指定它要的是什么,避免了数据后去的冗余或者不足。和RESTful API对比一下,每一个客户端都会对应很多个RESTful API或者一个API要服务很多个客户端。所以说GraphQL是很好的查询语言。所有的operation、参数和所有可以查询的字段都需要在GraphQL server上定义、实现。
GraphQL还解决了另外一个问题。假设我们要查询product_categories
和相关的products
。在一个RESTful server上你可以实现一个API,返回全部的数据。但是,大多数的情况下,客户端会先请求product_categories
之后在其他的请求中获取相关的某些products
。
我们看看使用GraphQL可以怎么做:
query {
product_categories {
name
products {
name
price
}
}
}
我们这一次没有使用参数。在查询中我们指定了我么需要每一个product_category
的name
,还有所有的这个类别下的产品,每个产品的字段也都分别指定。返回的结果:
{
"data": {
"product_categories": [
{
"name": "Acoustic Drums",
"products": [
{
"name": "Mapex Black Panther Velvetone 5-pc Drum Shell Kit",
"price": 2949.09
},
{
"name": "Pearl MCX Masters Natural Birdseye Maple 4pc Shell Pack with 22\" Kick",
"price": 1768.33
}
]
},
{
"name": "Cymbals",
"products": [
{
"name": "Sabian 18\" HHX Evolution Crash Cymbal - Brilliant",
"price": 319
},
{
"name": "Zildjian 20\" K Custom Dry Light Ride Cymbal",
"price": 396.99
},
{
"name": "Zildjian 13\" K Custom Dark Hi Hat Cymbals",
"price": 414.95
}
]
}
]
}
}
查询的嵌套没有限制,全看我们的查询和server的实现。比如西面的例子完全合法:
{
purchases(client_id: 1) {
date
quantity
total
product {
name
price
product_category {
name
}
}
client {
name
dob
}
}
}
这里我们请求server返回某个客户的purchases
。查询里不仅指定了purchase
的字段,还指定了相关的product
,product_category
的名称。
GraphQL有非常重要的一个特点:强类型。
每一个GraphQL server都要定义类型系统。查询实在这个类型系统的上下文中执行的。
也就是说,你可以查询值类型:Int
, Float
, String
, Boolean
和ID
。
而上例中的purchase
里的字段,product
、client
和product_category
都是对象类型(Object Type)的。这些类型都需要我们自己定义。
由于GraphQL查询都是结构化的,信息也是类树结构展示的。值类型(Scalar Type)的可以理解为叶子,对象类型(Object Type)可以理解为树干。
操作(Operation)和字段别名
在GraphQL查询中可以为Operation里的字段指定别名。比如查询里指定了字段cymbal_size
,但是客户端只能接受diameter
。另外查询的返回结果都包含在以operation名称为key的对象里,所以这个名称也可以设置一个别名:
{
my_product: product(id: 3) {
id
name
diameter: cymbal_size
}
}
返回的数据:
{
"data": {
"my_product": {
"id": "3",
"name": "Zildjian 13\" K Custom Dark Hi Hat Cymbals",
"diameter": "13\""
}
}
}
Fragments
现在,客户端APP要获取另个分开的list: drum sets
和cymbals
。在GraphQL里你不会被限制在一个operation里。同时我们也可以像设置字段别名那样设置返回结果的别名:
query {
drumsets: product(product_category_id: 1) {
id
name
manufacturer
price
pieces
shell_size
shell_type
}
cymbals: products(product_category_id: 2) {
id
name
manufacturer
price
cymbal_size
}
}
你可能已经注意到,在查询的两个对象中都包含了字段:id
、name
、manufacturer
、price
。
为了避免重复字段,我们可以使用GraphQL提供的Fragments。我们来把重复的字段都提出来,放到一个fragment里:
query {
drumsets: products(product_category_id: 1) {
...ProductCommonFields
prices
shell_size
shell_type
}
cymbals: products(product_category_id: 2) {
...ProductCommonFields
cymbal_size
}
}
fragment ProductCommonFields on Product {
id
name
manufacturer
price
}
要使用一个Fragment就使用操作符:...
。
变量(Variable)
我们要减少查询语句中的重复,我们来看看另外的一个例子该如何处理:
client(id: 1) {
name
dob
}
purchasses(client_id: 1) {
date
quantity
total
product {
name
price
product_category {
name
}
}
client {
name
dob
}
}
我们使用两个operation查询server,并且每个都包含了client_id
参数。如果可以把这个集中到一起就非常好了。我们可以使用GraphQL的变量来实现这个效果。我们来添加一个clientID
变量。
query($clientId: Int) {
client(id: $clientId) {
name
dob
}
purchases(client_id: $clientId) {
date
quantity
total
product {
name
price
product_category {
name
}
}
client {
name
dob
}
}
}
我们在operation的前面定义了变量,然后我们就可以在整个查询中使用这个变量了。 为了使用变量的定义,我们需要在查询的时候附带变量值的JSON。
{
"clientId": 1
}
当然,我们也可以指定一个默认值:
query ($date: String = "2017/01/28") {
purchases(date: $date) {
date
quantity
total
}
}
Mutation(修改)
GraphQL不仅可以用来查询数据,也可以创建、更新和销毁数据。当然和查询一样,这些也需要server端有对应的实现。增、删、改一类的operation在GraphQL里统称为Muration(修改)。我们就通过几个例子来演示一下mutation。
mutation {
create_client (
name: "查理大叔"
dob: "2017/01/28"
) {
id
name
dob
}
}
我们现在指定operation的类型为mutation,而不是query。在create_client
操作里我们传入了创建一个client
需要的数据,并最终返回一个查询集合:
{
"data": {
"create_client": {
"id": "5",
"name": "查理大叔",
"dob": "2017/01/28"
}
}
}
上面的数据有一点错误,生日不对。下面就来用更新来fix这个错误:
mutation {
update_client (
id: 5
dob: "1990/01/01"
) {
id
name
dob
}
}
最后,如果我们要删除这个数据可以这样:
mutation {
destroy_client(id: 5) {
name
dob
}
}
注意:create_client
、update_client
和destroy_client
这些operation都是在GraphQL server实现好的。如果有什么方法可以知道GraphQL server都实现了什么方法不是很好,是的有GraphQL的doc可以查看。
定义说明
GraphQL的一个非常好的特性就是,它会根据已经定义好的类型系统来自动生成出一个说明文档。这样你就不用一次一次的翻看代码,而直接查看文档来了解operation的全部实现细节。如果你用的是express-graphql
, 并设置graphiql
为true
的话,那么就会生成一个web的调试界面。在最右侧可以直接使用doc:
app.use('/mobile/egoods', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
pretty: IS_DEVELOPMENT,
}))
或者,也可以使用对于应定义好的schema的查询,如:
{
__schema {
queryType {
name
fields {
name
}
}
}
}
结果为:
{
"data": {
"__schema": {
"queryType": {
"name": "Query",
"fields": [
{
"name": "client"
},
{
"name": "clients"
},
{
"name": "product"
},
{
"name": "product_categories"
},
{
"name": "product_category"
},
{
"name": "products"
}
]
}
}
}
}
对于mutation
类型的操作也是一样的:
{
__schema {
mutationType {
name
fields {
name
}
}
}
}
查询的结果为:
{
"data": {
"__schema": {
"mutationType": {
"name": "Mutation",
"fields": [
{
"name": "create_client"
},
{
"name": "destroy_client"
},
{
"name": "update_client"
}
]
}
}
}
}
就像上文展示的一样,你还可以查询很多其他的内容。比如:
{
__schema {
queryType {
name
fields {
name
args {
name
}
}
}
}
}
我们来简单的看看结果是什么样的:
{
"data": {
"__schema": {
"queryType": {
"name": "Query",
"fields": [
{
"name": "clients",
"args": [
{
"name": "ids"
},
{
"name": "name"
},
{
"name": "dob"
}
]
},
{
...
},
{
"name": "products",
"args": [
{
"name": "ids"
},
{
"name": "product_category_id"
},
{
"name": "order"
},
{
"name": "limit"
}
]
}
]
}
}
}
}
你会看到server实现了一个clients
的查询operation,参数为ids
、name
和dob
。第二个操作是products
,在这里的参数是ids
、product_category_id
和order
、limit
。
最后
GraphQL可以让我们定义更加便捷的查询Server。如果你有兴趣学习的话,我强烈的建议你可以读一读GraphQL的定义说明,然后试着自己实现一个GraphQL server。
Graphql入门的更多相关文章
- Vue项目中GraphQL入门学习与应用
1.GraphQL是什么,能干什么? 正如官网所说,GraphQL是一种用于API查询的语言.Facebook 的移动应用从 2012 年就开始使用 GraphQL.GraphQL 规范于 2015 ...
- GraphQL入门有这一篇就足够了
GraphQL入门有这一篇就足够了:https://blog.csdn.net/qq_41882147/article/details/82966783 版权声明:本文为博主原创文章,遵循 CC 4. ...
- GraphQL入门1
1. 资源: 主站: https://graphql.org/ 中文站: http://graphql.cn 入门视频: https://graphql.org/blog/rest-api-graph ...
- GraphQL 入门介绍
写在前面 GraphQL是一种新的API标准,它提供了一种更高效.强大和灵活的数据提供方式.它是由Facebook开发和开源,目前由来自世界各地的大公司和个人维护.GraphQL本质上是一种基于api ...
- GraphQL入门3(Mutation)
创建一个新的支持Mutation的Schema. var GraphQLSchema = require('graphql').GraphQLSchema; var GraphQLObjectType ...
- GraphQL入门2
将服务器端的代码升级了一下: var GraphQLSchema = require('graphql').GraphQLSchema; var GraphQLObjectType = require ...
- 《分享》Graphql入门与实践
最近项目用到了graphql,学习了一些并在公司做了一个小分享,希望对你有帮助 一.介绍 Graphql是一种面向数据的API查询语言 Graphql给前端提供一种强力的查询工具,我们可以根据自己定义 ...
- GraphQL快速入门教程
摘要: 体验神奇的GraphQL! 原文:GraphQL 入门详解 作者:MudOnTire Fundebug经授权转载,版权归原作者所有. GraphQL简介 定义 一种用于API调用的数据查询语言 ...
- 前端从零开始学习Graphql
学习本姿势需要电脑装有node,vue-cli相关环境,以及要有node,express,koa,vue相关基础 本文相关demo的github地址: node服务:https://github.co ...
随机推荐
- 第四弹:overfeat
overfeat是在AlexNet出现后,推出来的模型,其不仅用于物体分类,来用于定位,检测等,可以说是一个涉及很多应用场景的通用模型,值得看看. 本文将从两个方面来讲解,第一部分从论文角度来说一说, ...
- [Unity Shader]光照模型对物体的假设
什么是光照模型 光照模型就是模拟光在物体间的传递过程,以确保物体可见表面每一点的亮度和颜色. 当光照射到一个物体表面时,光可能被吸收.反射或折射.反射和折射的光使物体可见.如果入射光全部被吸收,物体将 ...
- mustache.js使用基本(三)
作者:zccst 本节要点是子模块(partials)和分隔符(delimiter)等 1,子模块(partials) /* {{>partials}}以>开始表示子模块,如{{> ...
- iOS推送跳转AppDelegate跳转VC
在开发项目中,会有这样变态的需求: 推送:根据服务端推送过来的数据规则,跳转到对应的控制器 feeds列表:不同类似的cell,可能跳转不同的控制器(嘘!产品经理是这样要求:我也不确定会跳转哪个界面哦 ...
- enum的java例子
Grade.java package com.zhiyuan.myenum; /** * <p>Title: 枚举类 * <p>Company: * @description ...
- [TJOI2013]单词
2755: [TJOI2013]单词 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 6 Solved: 3[Submit][Status][Web B ...
- 关于ios 推送功能的终极解决
刚刚做了一个使用推送功能的应用 遇到了一些问题整的很郁闷 搞了两天总算是弄明白了 特此分享给大家 本帖 主要是针对产品发布版本的一些问题 综合了网上一些资料根据自己实践写的 不过测试也可以看看 首先要 ...
- C语言-switch语句
switch (表达式的值) { case 1: 语句1 break; case 2: 语句2 break; case 3: 语句3 break; case 4: 语句4 break; ...... ...
- 前端面试题整理(html篇)
1.Doctype作用?标准模式与兼容模式各有什么区别? <!DOCTYPE>声明位于位于HTML文档中的第一行,处于 <html> 标签之前.告知浏览器的解析器用什么文档标准 ...
- ECshop中的session机制理解
ECshop中的session机制理解 在网上找了发现都是来之一人之手,也没有用自己的话去解释,这里我就抛砖引玉,发表一下自己的意见,还希望能得到各界人士的指导批评! 此session机制不需 ...