GraphQL

官方描述:

GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

优点

  1. GraphQL可以让我们通过请求控制返回的字段,以此来减少restful api的设计理念带来的请求多次的问题。

    比如我们要获取指定id的文章相关信息,包括标题、作者、发布时间以及前两条评论;同时加载当前用户信息。
// 两趟查询,难以拓展
GET /user/111
GET /article/1001?comment=2
// 一趟查询,易于扩展
{
article (id: 1001){
title,
author,
time,
comments (first: 2)
nickname,
time,
content
}
},
user (id: 111){
nickname,
photo,
sign
}
}
  1. 可拓展性

    前端自由选择返回
  2. 不需要额外代码处理冗余字段
  3. 提供 schema

    schema 可以在运行时被获取到, 类似thrift的idl文件,比较清楚,简单的方法甚至不需要文档。
  4. 调试比较方便

缺点

  1. 缓存麻烦

    https://graphql.cn/learn/caching/

    Relay 和 apollo-client 是两个graphql的前端模块,可以帮你在前端缓存数据。
  2. GraphQL 在前端如何与视图层、状态管理方案结合,目前也只有 React/Relay 这个一个官方方案。

    换句话说,如果你不是已经在用 Node + React 这个技术栈,引入 GraphQL 成本略高,风险也不小,这就很大程度上限制了受众。

    而且 FB 官方就只有一个 Node.js 的 reference implementation,其他语言都是社区做的。
  3. 每一个 field 都对数据库直接跑一个 query,会产生大量冗余 query,虽然网络层面的请求数被优化了,但数据库查询可能会成为性能瓶颈。

    FB 本身没有这个问题,因为他们内部数据库这一层也是抽象掉的,写 GraphQL 接口的人不需要顾虑 query 优化的问题。

    如何解决?

    DataLoader, DataLoader 的主要功能是 batching & caching,帮你合并请求。
  4. 需要服务端的全力配合
  5. GraphQL不存在鉴权方案,需要自行解决

get start

GraphQL为express和koa提供了插件,可以方便的搭建GraphQL服务器。

看下面的代码:

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql'); // 使用 GraphQL schema language 构建 schema
var schema = buildSchema(`
input MessageInput {
content: String
author: String
} type Message {
id: ID!
content: String
author: String
} type Query {
getMessage(id: ID!): Message
} type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
`); // 如果 Message 拥有复杂字段,我们把它们放在这个对象里面。
class Message {
constructor(id, {content, author}) {
this.id = id;
this.content = content;
this.author = author;
}
} // 映射 username 到 content
var fakeDatabase = {}; var root = {
getMessage: function ({id}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
},
createMessage: function ({input}) {
// Create a random id for our "database".
var id = require('crypto').randomBytes(10).toString('hex'); fakeDatabase[id] = input;
return new Message(id, input);
},
updateMessage: function ({id, input}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// This replaces all old data, but some apps might want partial update.
fakeDatabase[id] = input;
return new Message(id, input);
},
}; var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000, () => {
console.log('Running a GraphQL API server at localhost:4000/graphql');
});

我们通过GraphQL提供的语法,建立一个schema,类似typescript的interface。

有多种基本类型:ID, String, Int, []。

Query是查询操作,Mutation是增删改操作。

所以这里,我们提供了一个getMessage的方法,返回Message类型的信息。

Mutation类型这里我们提供了createMessage,和updateMessage两个方法。

定义完schema,还需要定义方法的处理:

定义root对象进行函数处理。

执行node index.js。然后访问localhost:4000/graphql就可以看到相应的调试页面。(前提是graphiql:true)。



这个调试页面还是很方便的。

打开调试页面,先create一个message:



然后查询这个message:

type 为query的时候,可以不写query。

前端请求

var dice = 1;
var sides = 6; var query = `query RollDice($dice: Int!, $sides: Int) {
rollDice(numDice: $dice, numSides: $sides)
}`; fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
query,
variables: { dice, sides },
})
})
.then(r => r.json())
.then(data => console.log('data returned:', data));

这是官网给的试例。fetch请求,把query传过去就可以啦,如果请求的是个函数,需要传参variables。如上dice和sides两个参数

连接数据库

这里给个连接mysql的schema和rootValue


var { buildSchema } = require('graphql'); const mysqlCon = require('./mysql'); // 使用 GraphQL schema language 构造一个 schema
let count = 0;
var schema = buildSchema(`
type UserInfo {
id: ID!
name: String
uid: Int
age: Int
sex: String
createdTime: String
updatedTime: String
description: String
}
type Query {
getUsers: [UserInfo]
getUserById(id: ID!): UserInfo
}
type Mutation {
invokeCount: Int
}
`); // root 为每个端点入口 API 提供一个解析器
var root = {
async getUsers() {
count += 1;
let users = await mysqlCon.pifySelect('select * from Tab_User_Info');
console.log(users);
return users;
},
async getUserById({id}) {
let users = await mysqlCon.pifySelect(`select * from Tab_User_Info where id=${id}`)
return users[0];
},
invokeCount() {
return count;
}
}; module.exports = {
root,
schema,
}

mysql.js

const mysql = require('mysql');

const connection = mysql.createConnection({
host: '127.0.0.1',
port: 3306,
user: 'root',
password: '123456',
database: 'Test_User'
}); connection.connect(function(err) {
if (err) {
console.error('error: ' + err.stack);
return;
}
}); Object.defineProperty(connection, 'pifySelect', {
value: function(sql) {
return new Promise((resolve, _)=>{
connection.query(sql, function (error, results) {
if (error) console.log('mysql select err:', error);
resolve(results);
});
})
}
}) module.exports = connection

用docker搞个mysql环境:

docker pull mysql:5.6
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6

docker exec -it mysql bash进入bash然后初始化一下mysql,插几个数据用来操作。

用koa-graphql或者express-graphql启一个服务,就可以直接访问啦。

使用方

facebook, twitter,github,我们公司(toutiao)部分业务在用。

GraphQL的更多相关文章

  1. Facebook的Web开发三板斧:React.js、Relay和GraphQL

    2015-02-26 孙镜涛  InfoQ Eric Florenzano最近在自己的博客上发表了一篇题为<Facebook教我们如何构建网站>的文章,他认为软件开发有些时候需要比较大的跨 ...

  2. facebook graphql

    思想先进,前端直接从后台调用所需要的数据. 最简单的理解: 从"select * from 学生表" 进化为"select name, sex from 学生表" ...

  3. Graphql介绍(Introduction to GraphQL)

    Introduction to GraphQL  GraphQL介绍 Learn about GraphQL, how it works, and how to use it in this seri ...

  4. graphql 新API 开发方式

    我们知道 GraphQL 使用 Schema 来描述数据,并通过制定和实现 GraphQL 规范 定义了支持 Schema 查询的 DSQL (Domain Specific Query Langua ...

  5. [GraphQL] Use GraphQLNonNull for Required Fields

    While certain fields in a GraphQL Schema can be optional, there are some fields or arguments that ar ...

  6. [GraphQL] Use Arguments in a GraphQL Query

    In GraphQL, every field and nested object is able to take in arguments of varying types in order to ...

  7. [GraphQL] Write a GraphQL Schema in JavaScript

    Writing out a GraphQL Schema in the common GraphQL Language can work for simple GraphQL Schemas, but ...

  8. [GraphQL] Serve a GraphQL Schema as Middleware in Express

    If we have a GraphQL Schema expressed in terms of JavaScript, then we have a convenient package avai ...

  9. [GraphQL] Use GraphQL's List Type for Collections

    In order to handle collections of items in a GraphQL Schema, GraphQL has a List Type. In this video, ...

  10. [GraphQL] Use GraphQL's Object Type for Basic Types

    We can create the most basic components of our GraphQL Schema using GraphQL's Object Types. These ty ...

随机推荐

  1. eclipse建立工作集管理项目

    废话不多说,直接上图 然后新建java working set管理项目,让自己的项目清晰明了

  2. JavaScript基础-3

    3 运算符 按照个数分类可分为:一元运算符.二元运算符.三元运算符: 按照功能分类可分为:算数运算符.自增运算符.比较运算符.逻辑运算符.赋值运算符: 3.1 算数运算符 算术运算符包含了加减乘除,符 ...

  3. ubuntu server 16.04 开启root密码登录

    0x00 ubuntu server 16.04 开启root密码登录 由于众多VPS默认使用证书验证登录,虽然安全但使用十分不便,所以特提供开启root用户并使用密码登录方法. 0x01 为root ...

  4. C# ComboBox绑定值问题

    使用这种方式始终绑定值有问题: cbxSchool.DataSource = schoolList; cbxSchool.DisplayMember = "school_name" ...

  5. 从0开始的Python学习019更多的Python内容2

    书接上文,接演Python全传 话说学了这么多Python的基础知识,也该写一点让别人看不懂的代码了. lambda lambda表达式,是一个方法的简化形似,它没有自己的代码块,它后面的语句就是它的 ...

  6. python类的继承、封装和多态

    摘自https://www.cnblogs.com/evablogs/p/6724477.html 继承 1 2 3 4 5 6 7 8 class Person(object):     def _ ...

  7. July 11th, 2018. Wednesday, Week 28th.

    It is during our darkest moments that we must focus to see the light. 越是在艰难的时候就越要着眼于光明. From Aristol ...

  8. [题解]洛谷P2709 小B的询问

    地址 是一道莫队模板题. 分析 设\(\text{vis[i]}\)表示元素\(\text{i}\)出现的次数 当一个元素进入莫队时,它对答案的贡献增加.有\(\delta Ans=(X+1)^2-X ...

  9. ansible_playbook 一键搭建集群架构

    目录 基础优化 SSH.Ansible,批量管理服务项目 剧本开始-----.10分钟左右 mail.yaml base.yaml rsync.yaml nfs.yaml web.yaml tweb. ...

  10. Docker部署脚本

    实现 1.检查内核版本 2.检查docker是否已安装 3.安装docker,如因网络等原因失败循环安装至安装完成 #!/bin/bash #file:docker_install.sh #From: ...