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. Java 处理 multipart/mixed 请求

    一.multipart/mixed 请求   multipart/mixed 和 multipart/form-date 都是多文件上传的格式.区别在于,multipart/form-data 是一种 ...

  2. Spring MVC(二)基于标注的MVC

    1.基于标注的Spring MVC 1.1 建立一个项目导入jar包(ioc aop mvc) 拷贝容器对应的配置文件到src下 在WEB-INF建立一个login.jsp 1.2 在web.xml ...

  3. selenium+python自动化测试系列---基础知识篇(1、HTML基础知识1)

    1.什么是HTML HTML是一种描述网页的语言.HTML指超文本标记语言(Hyper Text Markup Language),它不是一种编程语言,而是一种标记语言(markup language ...

  4. (七) Keras 绘制网络结构和cpu,gpu切换

    视频学习来源 https://www.bilibili.com/video/av40787141?from=search&seid=17003307842787199553 笔记 首先安装py ...

  5. Java:配置环境(Mac)——Eclipse;修改JDK版本后,Eclipse打不开

    1.官网下载 选择一个速度快的镜像 推荐东软这个 2.双击下载的安装包,下一步 其中有一步是选择Eclipse版本,SE选第一个,EE第二个.仔细审题吧. 3.配置JDK 应用.关闭 4.测试:写个H ...

  6. 彻底卸载注册表、流氓软件的工具Uninstall Tool

    Your Uninstaller 和Uninstall Tool都可以卸载Windows系统卸载不干净的软件和注册表驱动等 Uninstall Tool下载

  7. Python正则表达式很难?一篇文章搞定他,不是我吹!

    1. 正则表达式语法 1.1 字符与字符类 1 特殊字符:.^$?+*{}| 以上特殊字符要想使用字面值,必须使用进行转义 2 字符类 1. 包含在[]中的一个或者多个字符被称为字符类,字符类在匹配时 ...

  8. php 7.1 新特性解析

    php 7.1 新特性解析 返回值和传入参数可以指定为 null <?php function testReturn(): ?string { return 'elePHPant'; } var ...

  9. eclipse java formater 配置详解

    comment.insert_new_line_before_root_tags(insert/do_not_insert):在Javadoc根标记块前插入空行,默认为insert: insert_s ...

  10. python新手菜鸟之基础篇

    s=0 for i in range(1,101): s += i else: print(s) def main(n): '''打印菱形图形''' for i in range(n): print( ...