GraphQL
GraphQL
官方描述:
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
优点
- 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
}
}
- 可拓展性
前端自由选择返回 - 不需要额外代码处理冗余字段
- 提供 schema
schema 可以在运行时被获取到, 类似thrift的idl文件,比较清楚,简单的方法甚至不需要文档。 - 调试比较方便
缺点
- 缓存麻烦
https://graphql.cn/learn/caching/
Relay 和 apollo-client 是两个graphql的前端模块,可以帮你在前端缓存数据。 - GraphQL 在前端如何与视图层、状态管理方案结合,目前也只有 React/Relay 这个一个官方方案。
换句话说,如果你不是已经在用 Node + React 这个技术栈,引入 GraphQL 成本略高,风险也不小,这就很大程度上限制了受众。
而且 FB 官方就只有一个 Node.js 的 reference implementation,其他语言都是社区做的。 - 每一个 field 都对数据库直接跑一个 query,会产生大量冗余 query,虽然网络层面的请求数被优化了,但数据库查询可能会成为性能瓶颈。
FB 本身没有这个问题,因为他们内部数据库这一层也是抽象掉的,写 GraphQL 接口的人不需要顾虑 query 优化的问题。
如何解决?
DataLoader, DataLoader 的主要功能是 batching & caching,帮你合并请求。 - 需要服务端的全力配合
- 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的更多相关文章
- Facebook的Web开发三板斧:React.js、Relay和GraphQL
2015-02-26 孙镜涛 InfoQ Eric Florenzano最近在自己的博客上发表了一篇题为<Facebook教我们如何构建网站>的文章,他认为软件开发有些时候需要比较大的跨 ...
- facebook graphql
思想先进,前端直接从后台调用所需要的数据. 最简单的理解: 从"select * from 学生表" 进化为"select name, sex from 学生表" ...
- Graphql介绍(Introduction to GraphQL)
Introduction to GraphQL GraphQL介绍 Learn about GraphQL, how it works, and how to use it in this seri ...
- graphql 新API 开发方式
我们知道 GraphQL 使用 Schema 来描述数据,并通过制定和实现 GraphQL 规范 定义了支持 Schema 查询的 DSQL (Domain Specific Query Langua ...
- [GraphQL] Use GraphQLNonNull for Required Fields
While certain fields in a GraphQL Schema can be optional, there are some fields or arguments that ar ...
- [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 ...
- [GraphQL] Write a GraphQL Schema in JavaScript
Writing out a GraphQL Schema in the common GraphQL Language can work for simple GraphQL Schemas, but ...
- [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 ...
- [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, ...
- [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 ...
随机推荐
- dubbo-源码分析Provider
Dubbo provider启动原理: 当我们的dubbo启动我们的spring容器时spring 初始化容器的时候会查找META-INF/spring.handles文件查找对应的Namespace ...
- pycharm中Django的安装和简单使用
一.安装: 1.点击File,找到setting选项 2.点击+号,进入下面界面 结束后,安装完成 二.创建Django项目 创建成功后,新项目左侧: templates:用于存储HTML文件 set ...
- Servlet--创建和配置Servlet
在web开发中,一般由Servlet进行数据流的控制,并通过HttpServletResponse对象对请求做出响应.创建的Servlet必须继承HttpServlet类,并实现doGet()和doP ...
- 重拾《 两周自制脚本语言 》- Eclipse插件实现语法高亮
源码库: program-in-chinese/stone-editor-eclipse 参考: FAQ How do I write an editor for my own language? D ...
- 如何让nextcloud支持avi文件在线播放
默认的nextcloud是不支持avi文件播放的,google查了一圈,都说是没法支持. 然而我觉得都是html5写的,为啥偏偏不支持. 查了一些资料,发现还是官方的代码少写了东西,可能是没考虑那么全 ...
- Android 离线人脸识别 ArcFace 2.0 Demo开发分享
环境要求 1.运行环境 armeabi-v7a 2.系统要求 Android 5.0 (API Level 21)及以上 3.开发环境 Android Studio 下载地 ...
- 人脸检测识别,人脸检测,人脸识别,离线检测,C#源码
百度网盘地址 微云地址 使用虹软人工智能开放平台技术开发完成
- Jmeter分布式部署
当单机没有足够能力来模拟较重的负载,可以使用jmeter分布式测试功能, 通过一个Jmeter控制台来远程控制多个Jmeter引擎完成测试. 每个线程均独立运行测试计划.因此,线程组常用来模拟并发用户 ...
- NPM -- 初探--01
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并 ...
- Aspnet mvc移除WebFormViewEngine
为了提高mvc的速度,在Global.asax中移除WebFormViewEngine protected void Application_Start() { RemoveWebFormEngine ...