一、什么是GrapQL
1.介绍
GraphQL是一种用于API查询的语言,在对于Graph(图状数据结构)进行查询的时候,有特别的优势,所以叫做GraphQL。在对于API中的数据提供了一套利于理解的完整描述,使得客户端可以准确的获取想要的数据,没有任何的冗余,并且不和任何特定的数据库或者存储引擎绑定,而是依靠现有的代码和数据支撑,并且可以运行在任何后端框架和编程语言上。
2.特点
- 请求的数据不多不少
- 获取多个资源只需要一个请求
- 描述所有可能的类型的系统,便于维护,可以根据需求平滑的添加和隐藏字段
3.为什么使用Graphql
当后端返回数据过多时,前端只用到了一部分,或者说后端返回的数据过少,前端需要用多个请求获取数据来组成数据,前后端工程师需要反复沟通数据结构。
二、使用GraphQL
首先需要基于express来搭建一个GraphQL的服务器,我们需要使用express-graphql和graphql,所以需要下载以下三个包
npm install express express-graphql graphql
graphql是一个支持库,express-graphql是对应的http服务器,express则是node的服务框架
新建一个index.js的文件,里面包含了如下代码
var express = require('express');
var { graphqlHTTP } = require('express-graphql');
var { buildSchema } = require('graphql');
// 定义schema,查询和类型
var schema = buildSchema(`
type Query {
hello: String
}
`);
// 查询对应的处理器
var root = { hello: () => 'Hello world!' };
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'));
然后在控制台中输入node index.js运行以上代码,并打开浏览器访问http://localhost:4000/graphql
这时候就可以看到graphql自带的调试工具,点开右上角的Docs就可以看到我们的query和它的返回值
在左侧输入hello就可以查询到我们query所返回的Hello world!
三、类型
1. 基本类型
在GraphQL中支持一些基本的变量类型
Int:有符号 32 位整数。Float:有符号双精度浮点值。String:UTF‐8 字符序列。Boolean:true或者false。ID:ID 标量类型表示一个唯一标识符,通常用以重新获取对象或者作为缓存中的键。ID 类型使用和 String一样的方式序列化;然而将其定义为 ID 意味着并不需要人类可读型。Array: [Int] 表示里是int类型的数组 默认情况下所有的类型都是可以为空的,意味着所有的标量类型都可以返回空,使用感叹后可以标记一个类型不可以为空,如String!表示非空字符串。
2. 对象类型
如果想要返回复杂类型需要query中定义,如
type User{
id: Id!
name: String
age: Int
email: String
}
type Query {
getUser(id: Id!): User
}
四、操作类型
GraphQL 的操作类型可以是 query、mutation 或 subscription,描述客户端希望进行什么样的操作
- query 查询:获取数据,比如查找,CRUD 中的 R
- mutation 变更:对数据进行变更,比如增加、删除、修改,CRUD 中的 CUD
- substription 订阅:当数据发生更改,进行消息推送
五、客户端请求
已上述getUser为例,graphql还是通过http请求来传递数据,通过请求/graphql就可以返回user的数据
/**
* 服务端
*/
const express = require("express")
const {
graphqlHTTP
} = require("express-graphql");
const {
buildSchema
} = require("graphql");
var schema = buildSchema(`
"""
用户信息
"""
type User {
"姓名"
name: String
"年龄"
age: Int
"性别"
gender: Int
}
type Query {
hello: String
world: String
getUser(id: String): User
}
`)
let root = {
hello() {
return "hello-world"
},
world() {
return "world"
},
getUser({
id
}) {
const userList = {
1: {
name: "张三",
age: 18,
gender: 0
},
2: {
name: "李四",
age: 24,
gender: 31
}
}
return userList[id];
}
}
var app = express();
app.use("/graphql", graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}))
app.use(express.static('public'))
app.listen(4000, () => {
console.log("端口启动")
})
/**
客户端
*/
let query = `
query GetUser($id:String){
getUser(id:$id){
name
age
gender
}
}
`
let variables = {
id:"1"
}
fetch("/graphql",{
method: "POST",
headers:{
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
query: query,
variables: variables
})
}).then(res=>res.json()).then(e=>console.log(e))
成功返回用户数据
六、与数据库结合
在本地数据库中创建一个测试库,新建一个user表,里面的字段和之前的用户信息一样
create database test;
use test;
create table `user`(
`name` varchar(20),
`age` int,
`gender` varchar(2)
)ENGINE=InnoDB charset=utf8
通过npm install mysql下载mysql驱动,在服务端中引入mysql包,并连接上本地数据库
const mysql = require("mysql")
var pool = mysql.createConnection({
host: "localhost", // 数据库连接地址
user: "root", // 用户名
password: "123456", // 密码
database: "test" //数据库名称
})
先添加用户,在mutaion中新增addUser方法
var schema = buildSchema(`
input UserInput{
name: String
age: Int
gender: String
}
type Mutation {
addUser(input: UserInput): Boolean
}
`}
let root = {
addUser({
input
}) {
const data = {
name: input.name,
age: input.age,
gender: input.gender
}
return new Promise((res, rej) => {
pool.query("insert into user set ?", data, (err) => {
if (err) {
console.log(err);
return rej(false);
}
return res(true)
})
})
},
}
在调试器中调用addUser方法来添加用户
添加成功
然后我们在添加一个获取用户列表的方法
var schema = buildSchema(`
type User {
"姓名"
name: String
"年龄"
age: Int
"性别"
gender: Int
}
type Query {
userList: [User]
}
`}
let root = {
userList() {
return new Promise((res, rej) => {
pool.query("select name,age,gender from user", (err, item) => {
if (err) {
console.log("出错了", err)
return
}
return res(item)
})
})
}
}
七、总结
上面只使用了express来实现了graphql,后面可以通过其他编程语言来实现下,并且可以了解其中的语法解析的过程,使用下来感觉graphql是一个灵活的api请求,有方便的调试工具,前端可以自己组建想要的结果。但graphql只是一个web api的请求,只要在restful中出现过的安全问题,它都有可能也会出现,并且这个是个对前端友好的东西,实现起来需要后端服务的全力配合。