GraphQL 分享 实战篇

  1. 云栖社区>
  2. 博客>
  3. 正文

GraphQL 分享 实战篇

飞凡的陀螺 2018-03-31 08:38:00 浏览346
展开阅读全文

三种基本操作 Query(a read‐only fetch), Mutation(a write followed by a fetch), Subscription(订阅,不常用,适合长连接业务)

1. 起步,用express实现最简单的例子

运行一个GraphQL API Server

GraphiQL is a great tool for debugging and inspecting a server, so we recommend running it whenever your application is in development mode.


img_ef17567c3f9f4929ceab1fbba5152594.png
image.png

index.js

const express = require('express');
const graphqlHTTP = require('express-graphql');
const schema = require('./schema');
const app = express();
// 具体选项含义见文档
// https://github.com/graphql/express-graphql
app.use('/graphql', graphqlHTTP({
  schema: schema,
  graphiql: true,
}));

app.listen(12580);
console.log("please open http://localhost:12580/graphql")

schema.js

const {
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} = require('graphql');

const Query = new GraphQLObjectType({
  name: 'BlogSchema',
  description: 'Root of the Blog Schema',
  fields: () => ({
    echo: {
      type: GraphQLString,
      description: '回应你输入的内容',
      args: {
        message: {type: GraphQLString}
      },
      resolve: function(source, {message}) {
        return `hello: ${message}`;
      }
    },
  })
});


const Schema = new GraphQLSchema({
  query: Query,
});

module.exports = Schema;

注意点:

  • 上篇讲过GraphQL只是一套规范,目前官方只提供了JS版本,其他PHP,Go等其他语言都是社区实现的。

  • 当只有一种操作,并且是query,可以省去query操作名关键字


    img_921b3423a1e7b22c301ffd5b2b81c984.png
    image.png
  • 可以看到字段和字段参数要指定类型,因为GraphQL是强类型的。

  • 因为指定了参数类型是string,输入时必须要用双引号

  • 注意看调试面板的请求

GraphQL API server运行时,只要构造http请求就可以,传入不同的query参数,也能得到和在GraphiQL同样的结果


img_b61b665c7ab13a4f2704d296087f4949.png
image.png

2. 查询

2.1 变量

所有声明的变量都必须是标量、枚举型或者输入对象类型。


img_3550dc9258a1f6d443d074b9dbb5b174.png
image.png
默认变量

使用默认值


img_46b0b856bb15dd566dbb82067c3247d0.png
image.png

img_4277b8263177616f419b1f29cc0a60bf.png
image.png

覆盖默认值


img_ccd52e7b29ace7282018bec1ae57d97e.png
image.png

类型后面带个感叹号表示参数必填


img_90ef5af5ef6ad202d4cef0be3d7a8c06.png
image.png

2.2 别名

img_0bfab3892f6204d4efb07cdb25195013.png
image.png

2.3 片段

提取公众的部分
上面的查询,将共同的字段:id和name,提取成fragment


img_d77a5948d744b99b71f6a27669f445ee.png
image.png

2.4 指令

GraphQL内置两个核心指令,@skip@include
@skip(if: Boolean) 如果参数为 true,跳过此字段。
? 貌似参数必须要写默认值 ?

img_5aea95bf6a5725d358e40169826323bb.png
image.png

img_5830558c6ffd65dc38a124ea88dcddb8.png
image.png

3. 修改 Mutation

详见

4. 分页

分页的原理:定义一个Edges类型,包含node和cursor字段,Node保存查询列表内容,Cursor记录分页。以下面的Github例子

5. GitHub GraphQL API

打开 https://developer.github.com/v4/explorer/
先打开右侧的Docs浏览所有Query,发现有个名为search的query

img_67531cdde1e790a0b22b507e214b4180.png
image.png

他返回的是个 SearchResultItemConnection!类型,接着点进去

img_a8a9a3749843fdcf100d18611687ffd7.png
image.png

你会发现所有已Connection结尾的类型,其结果都包含pageInfo, edges, nodes

输入下面的内容,这个查询是返回包含"graphql"关键字的前三个仓库,并显示每个仓库的前3个issues的作者,头像信息。

{
  search(first: 3, query: "graphql", type: REPOSITORY) {
    codeCount
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      
      node {
        
        ... on Repository {
          nameWithOwner
          issues(first: 3) {
            nodes {
              author {
                avatarUrl
                login
                resourcePath
                url
              }
              title
            }
          }
        }
      }
    }
  }
  rateLimit {
    cost
    limit
    nodeCount
    resetAt
    remaining
  }
}

返回的结果类似

{
  "data": {
    "search": {
      "codeCount": 16287,
      "pageInfo": {
        "startCursor": "Y3Vyc29yOjE=",
        "endCursor": "Y3Vyc29yOjM=",
        "hasNextPage": true,
        "hasPreviousPage": false
      },
      "edges": [
        {
          "cursor": "Y3Vyc29yOjE=",
          "node": {
            "nameWithOwner": "facebook/graphql",
            "issues": {
              "nodes": [
                {
                  "author": {
                    "avatarUrl": "https://avatars0.githubusercontent.com/u/540892?v=4",
                    "login": "raymondfeng",
                    "resourcePath": "/raymondfeng",
                    "url": "https://github.com/raymondfeng"
                  },
                  "title": "Possibility of collaboration with LoopBack framework?"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars1.githubusercontent.com/u/825073?v=4",
                    "login": "luisobo",
                    "resourcePath": "/luisobo",
                    "url": "https://github.com/luisobo"
                  },
                  "title": "Pagination?"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars3.githubusercontent.com/u/71047?v=4",
                    "login": "KyleAMathews",
                    "resourcePath": "/KyleAMathews",
                    "url": "https://github.com/KyleAMathews"
                  },
                  "title": "Custom Sorting"
                }
              ]
            }
          }
        },
        {
          "cursor": "Y3Vyc29yOjI=",
          "node": {
            "nameWithOwner": "graphql-go/graphql",
            "issues": {
              "nodes": [
                {
                  "author": {
                    "avatarUrl": "https://avatars0.githubusercontent.com/u/78585?v=4",
                    "login": "sogko",
                    "resourcePath": "/sogko",
                    "url": "https://github.com/sogko"
                  },
                  "title": "Suggestion: Improve package discovery"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars2.githubusercontent.com/u/1064547?v=4",
                    "login": "ptomasroos",
                    "resourcePath": "/ptomasroos",
                    "url": "https://github.com/ptomasroos"
                  },
                  "title": "Why not wrap the C lib?"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars0.githubusercontent.com/u/1000404?v=4",
                    "login": "chris-ramon",
                    "resourcePath": "/chris-ramon",
                    "url": "https://github.com/chris-ramon"
                  },
                  "title": "Using graphql-go in other programs throws various errors."
                }
              ]
            }
          }
        },
        {
          "cursor": "Y3Vyc29yOjM=",
          "node": {
            "nameWithOwner": "Youshido/GraphQL",
            "issues": {
              "nodes": [
                {
                  "author": {
                    "avatarUrl": "https://avatars2.githubusercontent.com/u/2429244?v=4",
                    "login": "mrbarletta",
                    "resourcePath": "/mrbarletta",
                    "url": "https://github.com/mrbarletta"
                  },
                  "title": "How to manage a List of Posts"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars2.githubusercontent.com/u/2429244?v=4",
                    "login": "mrbarletta",
                    "resourcePath": "/mrbarletta",
                    "url": "https://github.com/mrbarletta"
                  },
                  "title": "No way to get requested fields of the object inside `resolve`"
                },
                {
                  "author": {
                    "avatarUrl": "https://avatars0.githubusercontent.com/u/971254?v=4",
                    "login": "larswolff",
                    "resourcePath": "/larswolff",
                    "url": "https://github.com/larswolff"
                  },
                  "title": "Minor documentation issue?"
                }
              ]
            }
          }
        }
      ]
    },
    "rateLimit": {
      "cost": 1,
      "limit": 5000,
      "nodeCount": 12,
      "resetAt": "2018-03-31T01:47:34Z",
      "remaining": 4995
    }
  }
}
  • 每个node包含一个cursor游标,不是数字,是唯一字符串
  • 如果想查下一页,直接修改query search,添加after参数。 search(first: 3, after:"Y3Vyc29yOjM=", query: "graphql", type: REPOSITORY) {
  • 关于实现原理,参考

最后欢迎 clone 我的仓库, 里面包含了所有例子。

网友评论

登录后评论
0/500
评论
飞凡的陀螺
+ 关注