Graphql初体验

356 阅读5分钟

一、什么是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!

image.png

三、类型

1. 基本类型

在GraphQL中支持一些基本的变量类型

  • Int:有符号 32 位整数。
  • Float:有符号双精度浮点值。
  • String:UTF‐8 字符序列。
  • Booleantrue 或者 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 的操作类型可以是 querymutationsubscription,描述客户端希望进行什么样的操作

  1. query 查询:获取数据,比如查找,CRUD 中的 R
  2. mutation 变更:对数据进行变更,比如增加、删除、修改,CRUD 中的 CUD
  3. 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))

成功返回用户数据

image.png

六、与数据库结合

在本地数据库中创建一个测试库,新建一个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方法来添加用户

image.png

image.png

添加成功

然后我们在添加一个获取用户列表的方法

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)
            })
        })
    }
}

image.png

七、总结

上面只使用了express来实现了graphql,后面可以通过其他编程语言来实现下,并且可以了解其中的语法解析的过程,使用下来感觉graphql是一个灵活的api请求,有方便的调试工具,前端可以自己组建想要的结果。但graphql只是一个web api的请求,只要在restful中出现过的安全问题,它都有可能也会出现,并且这个是个对前端友好的东西,实现起来需要后端服务的全力配合。