admin管理员组

文章数量:1026989

【GraphQL】

GraphQL介绍

  • GraphQL是Facebook开发的一种数据查询语言,并于2015年公开发布。它是REST API的替代品。
  • GraphQL既是一种用于API的查询语言也是一个满足你数据查询的运行时。GraphQL对你的API的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让API更容易地随着时间推移而演进。
  • 官网:/
  • 中文网:/
  • 特点:

1.请求需要的数据,不多不少
例如:account中有name,age,sex,department等,可以只取得需要的字段。
2.获取多个资源,只用一个请求
3.描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或者隐藏字段。

例如一个查询请求:

//GraphQL语法,后面会讲到
//会根据字段进行数据的获取,而不像REST直接将所有的字段进行返回,这是一个特别好的前端优化的点
query{getAccount(userId:1){name	//graphql语法会根据里面的字段取出对应的值agesex}
}

结果如下:

{“data”:{"getAccount":{"name":"xxx","age":"xxx","sex":"xxx"}}
}

GraphQL与restful对比

  1. restful:Representational State Transfer表属性状态转移。本质上就是用定义uri,通过api接口来取得资源。通用系统架构,不受语言限制。restful还是主流。
  2. 例子:饿了么接口


  3. restful一个接口只能返回一个资源,graphql一次可以获取多个资源。
  4. restful用不同的url来区分资源,graphql用类型区分资源。

使用express+GraphQL

  1. npm init -y //初始化一个package.json文件
  2. npm i express graphql express-graphql -S
  3. node helloWorld.js
  4. localhost:4000/graphql
  5. query{hello}
const express = require('express');
const graphqlHTTP = require('express-graphql');
const {buildSchema} = require('graphql');//Construct a schema,using GraphQL,schema language
//构建schema,这定义查询的语句和类型
const schema= buildSchema(type Account{name:Stringage:Intsex:String}type Query{hello:StringaccountName:Stringaccount:Account}
);//The root proyides a resolver function for each API
//定义查询所对应的resolver,也就是查询对应的处理器
const root={hello:()=>{return 'Hello World!';},accountName:()=>{return "test name";};account:()=>{return {name:"test name",age:11,sex:"test sex",}}
};const app = express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphql:true,	//是否启用调试界面,false就不能调试了,开发时是true,上线的话变为false
}))
app.listen(4000);

类型定义与返回值不一致时会报错

基本参数类型

  • 基本类型:String/Int/Float/Boolean/ID。可以在schema声明的时候直接使用。
  • [类型]代表数组,例如:[Int]代表整型数组。

参数传递

  • 和js传递参数一样,小括号内定义形参,但是注意:参数需要定义类型。
  • !(叹号)代表参数不能为空
type Query{rollDice(numDice:Int!,numSides:Int):[Int]
}

Test Demo:


自定义参数类型

  • GraphQL允许用户自定义参数类型,通常用来描述要获取的资源的属性。
type Account{name:Stringage:Intsex:Stringsalary(city:String):Int
}
type Query{account(name:String):Account	//定义一个Account属性,然后在Account类型中进行返回
}

GraphQL clients

  • 如何在客户端访问graphql的接口?
var username = 66;
//固定写法,Account($username:Int!),account(username:$username),$username和后端的username是一样的
var query = `query Account($username:Int!){account(username:$username)
}`;
fetch('/graphql',{method:'POST',headers:{'Content-Type':'application/json','Accept':'application/json',},//因为是post,数据从body出去body:JSON.stringify({query,variables:{username},})
})
.then(r=>r.json())
.then(data=>console.log('data returned',data));

后端代码

const express = require('express');
const {buildSchema} = require('graphql');
const graphql = require('express-graphql');
//定义schema,查询和类型
const schema = buildSchema(`type Account{name:Stringage:Intsex:Stringdepartment:Stringsalary(city:String):Int}type Query{getClassMates(classNo:Int!):[String]account(username:String):Account}
`)
//定义查询对应的处理器
const root={getClassMates({classNo}){const obj={31:['name1','name2','name3'],32:['name4','name5','name6']}return obj[classNo];},account({username}){const name=username;const sex='man';const age=11;const department='testdepartment';const salary=({city})=>{if(city==='北京'||city==='上海'||city==='广中'||city==='深圳'){return 10000;}return 2000;}return {name,sex,age,department,salary}}
}
const app=express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))
//公开文件夹,供用户访问静态资源
app.use(express.static("public")
app.listen(3000);

前端代码

  <!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body><button onclick="getData()">获取数据</button>
</body>
</html>
<script>function getData(){const query=`query Account($username:String,$city:String){account(username:$username){nameagesexsalary(city:$city)}}`const variables={username:"lisi",city:'深圳'}fetch('/graphql',{method:'POST',header:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({query:query,variables:variables})}).then(res=>res.json).then(data=>{console.log(data);})}
</script>

使用Mutations修改数据

  • 查询使用query,修改数据使用Mutation
    `
//input表示输入input AccountInput{name:Stringage:Intsex:Stringdepartment:Stringsalary:Int}type Mutation{//括号里是形参createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}

代码
小坑:

  1. 写mutation的话必须写query
const express = require('express');
const {buildSchema}=require('graphql');
const graphqlHTTP=require('express-graphql');
//定义schema,查询和类型,mutation
const schema=buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB={};
//定义查询对应的处理器
const root={account(){var arr=[];for(const key in fakeDB){arr.push(fakeDB[key])}return arr;},createAccount({input}){//相当于数据库的保存fakeDB[input.name]=input;//返回保存结果return fakeDB[input.name];},updateAccount({id,input}){//相当于数据库的更新const updateAccount=Object.assign({},fakeDB[id],input);fakeDB[id]=updateAccount;//返回数据库return updatedAccount;}
}
const app=express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))app.listen(3000)

认证与中间件(高级部分)

const express = require('express');
const {buildSchema}=require('graphql');
const graphqlHTTP=require('express-graphql');
//定义schema,查询和类型,mutation
const schema=buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB={};
//定义查询对应的处理器
const root={account(){var arr=[];for(const key in fakeDB){arr.push(fakeDB[key])}return arr;},createAccount({input}){//相当于数据库的保存fakeDB[input.name]=input;//返回保存结果return fakeDB[input.name];},updateAccount({id,input}){//相当于数据库的更新const updateAccount=Object.assign({},fakeDB[id],input);fakeDB[id]=updateAccount;//返回数据库return updatedAccount;}
}
const app=express();//增加一个判断权限的中间件const middleware=(req,res,next)=>{if(req.url.indexOf('/graphql')!=-1&&req.headers.cookie.indexOf('auth')){res.send(JSON.stringify({error:"您没有权限访问这个接口"}));return;}next();
}//使用中间件
app.use(middleware)app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))app.listen(3000)

Constructing Types(高级部分)

  1. 使用GraphQLObjectType定义type(类型)
    意义:方便后期维护
  2. 使用GraphQLObjectType定义query(查询)


3. 创建schema

高级_与数据库结合实战

const express = require('express');
const {buildSchema
} = require('graphql');
const graphqlHTTP = require('express-graphql');
const mysql = require('mysql');
// 
var pool = mysql.createPool({connectionLimit: 10,host: 'localhost',user: 'root',password: 'root',database: 'xxxx'
})//定义schema,查询和类型,mutation
const schema = buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountdeleteAccount(id:ID):BooleanupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB = {};
//定义查询对应的处理器
const root = {account() {return new Promise((resolve,reject)=>{pool.query('select name,age,sex,department from account',(err,results)=>{if(err){console.log('error',err.message);return;}const arr=[];for(const i=0;i<results.length;i++){arr.push({name:results[i].name,sex:results[i].sex,age:results[i].age,department:results[i].department,})}resolve(results);})})},createAccount({input}) {const data = {name: input.name,sex: input.sex,age: input.age,department: input.department}return new Promise((resolve, reject) => {pool.query('insert into accout set ?', data, (err) => {if (err) {console.log('error',err.message);return;}//返回保存结果resolve(data);})})},updateAccount({id,input}) {const data=input;return new Promise((resolve,reject)=>{pool.query('update account set?where name=?',[data,id],(err)=>{if(err){console.log('err',err.message);return;}resolve(data);})})    },deleteAccount({id}){return new Promise((resolve,reject)=>{pool.query('delete account where name=?',[id],(err)=>{if(err){console.log("err",err.message)reject(false);return;}resolve(true);})})}
}
const app = express();
//增加一个判断权限的中间件
const middleware = (req, res, next) => {if (req.url.indexOf('/graphql') != -1 && req.headers.cookie.indexOf('auth')) {res.send(JSON.stringify({error: "您没有权限访问这个接口"}));return;}next();
}
//使用中间件
app.use(middleware)app.use('/graphql', graphqlHTTP({schema: schema,rootValue: root,graphiql: true
}))app.listen(3000)

学习视频:=search&seid=9265460496338796424

【GraphQL】

GraphQL介绍

  • GraphQL是Facebook开发的一种数据查询语言,并于2015年公开发布。它是REST API的替代品。
  • GraphQL既是一种用于API的查询语言也是一个满足你数据查询的运行时。GraphQL对你的API的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让API更容易地随着时间推移而演进。
  • 官网:/
  • 中文网:/
  • 特点:

1.请求需要的数据,不多不少
例如:account中有name,age,sex,department等,可以只取得需要的字段。
2.获取多个资源,只用一个请求
3.描述所有可能类型的系统。便于维护,根据需求平滑演进,添加或者隐藏字段。

例如一个查询请求:

//GraphQL语法,后面会讲到
//会根据字段进行数据的获取,而不像REST直接将所有的字段进行返回,这是一个特别好的前端优化的点
query{getAccount(userId:1){name	//graphql语法会根据里面的字段取出对应的值agesex}
}

结果如下:

{“data”:{"getAccount":{"name":"xxx","age":"xxx","sex":"xxx"}}
}

GraphQL与restful对比

  1. restful:Representational State Transfer表属性状态转移。本质上就是用定义uri,通过api接口来取得资源。通用系统架构,不受语言限制。restful还是主流。
  2. 例子:饿了么接口


  3. restful一个接口只能返回一个资源,graphql一次可以获取多个资源。
  4. restful用不同的url来区分资源,graphql用类型区分资源。

使用express+GraphQL

  1. npm init -y //初始化一个package.json文件
  2. npm i express graphql express-graphql -S
  3. node helloWorld.js
  4. localhost:4000/graphql
  5. query{hello}
const express = require('express');
const graphqlHTTP = require('express-graphql');
const {buildSchema} = require('graphql');//Construct a schema,using GraphQL,schema language
//构建schema,这定义查询的语句和类型
const schema= buildSchema(type Account{name:Stringage:Intsex:String}type Query{hello:StringaccountName:Stringaccount:Account}
);//The root proyides a resolver function for each API
//定义查询所对应的resolver,也就是查询对应的处理器
const root={hello:()=>{return 'Hello World!';},accountName:()=>{return "test name";};account:()=>{return {name:"test name",age:11,sex:"test sex",}}
};const app = express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphql:true,	//是否启用调试界面,false就不能调试了,开发时是true,上线的话变为false
}))
app.listen(4000);

类型定义与返回值不一致时会报错

基本参数类型

  • 基本类型:String/Int/Float/Boolean/ID。可以在schema声明的时候直接使用。
  • [类型]代表数组,例如:[Int]代表整型数组。

参数传递

  • 和js传递参数一样,小括号内定义形参,但是注意:参数需要定义类型。
  • !(叹号)代表参数不能为空
type Query{rollDice(numDice:Int!,numSides:Int):[Int]
}

Test Demo:


自定义参数类型

  • GraphQL允许用户自定义参数类型,通常用来描述要获取的资源的属性。
type Account{name:Stringage:Intsex:Stringsalary(city:String):Int
}
type Query{account(name:String):Account	//定义一个Account属性,然后在Account类型中进行返回
}

GraphQL clients

  • 如何在客户端访问graphql的接口?
var username = 66;
//固定写法,Account($username:Int!),account(username:$username),$username和后端的username是一样的
var query = `query Account($username:Int!){account(username:$username)
}`;
fetch('/graphql',{method:'POST',headers:{'Content-Type':'application/json','Accept':'application/json',},//因为是post,数据从body出去body:JSON.stringify({query,variables:{username},})
})
.then(r=>r.json())
.then(data=>console.log('data returned',data));

后端代码

const express = require('express');
const {buildSchema} = require('graphql');
const graphql = require('express-graphql');
//定义schema,查询和类型
const schema = buildSchema(`type Account{name:Stringage:Intsex:Stringdepartment:Stringsalary(city:String):Int}type Query{getClassMates(classNo:Int!):[String]account(username:String):Account}
`)
//定义查询对应的处理器
const root={getClassMates({classNo}){const obj={31:['name1','name2','name3'],32:['name4','name5','name6']}return obj[classNo];},account({username}){const name=username;const sex='man';const age=11;const department='testdepartment';const salary=({city})=>{if(city==='北京'||city==='上海'||city==='广中'||city==='深圳'){return 10000;}return 2000;}return {name,sex,age,department,salary}}
}
const app=express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))
//公开文件夹,供用户访问静态资源
app.use(express.static("public")
app.listen(3000);

前端代码

  <!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head>
<body><button onclick="getData()">获取数据</button>
</body>
</html>
<script>function getData(){const query=`query Account($username:String,$city:String){account(username:$username){nameagesexsalary(city:$city)}}`const variables={username:"lisi",city:'深圳'}fetch('/graphql',{method:'POST',header:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({query:query,variables:variables})}).then(res=>res.json).then(data=>{console.log(data);})}
</script>

使用Mutations修改数据

  • 查询使用query,修改数据使用Mutation
    `
//input表示输入input AccountInput{name:Stringage:Intsex:Stringdepartment:Stringsalary:Int}type Mutation{//括号里是形参createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}

代码
小坑:

  1. 写mutation的话必须写query
const express = require('express');
const {buildSchema}=require('graphql');
const graphqlHTTP=require('express-graphql');
//定义schema,查询和类型,mutation
const schema=buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB={};
//定义查询对应的处理器
const root={account(){var arr=[];for(const key in fakeDB){arr.push(fakeDB[key])}return arr;},createAccount({input}){//相当于数据库的保存fakeDB[input.name]=input;//返回保存结果return fakeDB[input.name];},updateAccount({id,input}){//相当于数据库的更新const updateAccount=Object.assign({},fakeDB[id],input);fakeDB[id]=updateAccount;//返回数据库return updatedAccount;}
}
const app=express();
app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))app.listen(3000)

认证与中间件(高级部分)

const express = require('express');
const {buildSchema}=require('graphql');
const graphqlHTTP=require('express-graphql');
//定义schema,查询和类型,mutation
const schema=buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB={};
//定义查询对应的处理器
const root={account(){var arr=[];for(const key in fakeDB){arr.push(fakeDB[key])}return arr;},createAccount({input}){//相当于数据库的保存fakeDB[input.name]=input;//返回保存结果return fakeDB[input.name];},updateAccount({id,input}){//相当于数据库的更新const updateAccount=Object.assign({},fakeDB[id],input);fakeDB[id]=updateAccount;//返回数据库return updatedAccount;}
}
const app=express();//增加一个判断权限的中间件const middleware=(req,res,next)=>{if(req.url.indexOf('/graphql')!=-1&&req.headers.cookie.indexOf('auth')){res.send(JSON.stringify({error:"您没有权限访问这个接口"}));return;}next();
}//使用中间件
app.use(middleware)app.use('/graphql',graphqlHTTP({schema:schema,rootValue:root,graphiql:true
}))app.listen(3000)

Constructing Types(高级部分)

  1. 使用GraphQLObjectType定义type(类型)
    意义:方便后期维护
  2. 使用GraphQLObjectType定义query(查询)


3. 创建schema

高级_与数据库结合实战

const express = require('express');
const {buildSchema
} = require('graphql');
const graphqlHTTP = require('express-graphql');
const mysql = require('mysql');
// 
var pool = mysql.createPool({connectionLimit: 10,host: 'localhost',user: 'root',password: 'root',database: 'xxxx'
})//定义schema,查询和类型,mutation
const schema = buildSchema(`input AccountInput{name:Stringage:Intsex:Stringdepartment:String}type Account{name:Stringage:Intsex:Stringdepartment:String}type Mutation{createAccount(input:AccountInput):AccountdeleteAccount(id:ID):BooleanupdateAccount(id:ID!,input:AccountInput):Account}type Query{account:[Account]}
`)
const fakeDB = {};
//定义查询对应的处理器
const root = {account() {return new Promise((resolve,reject)=>{pool.query('select name,age,sex,department from account',(err,results)=>{if(err){console.log('error',err.message);return;}const arr=[];for(const i=0;i<results.length;i++){arr.push({name:results[i].name,sex:results[i].sex,age:results[i].age,department:results[i].department,})}resolve(results);})})},createAccount({input}) {const data = {name: input.name,sex: input.sex,age: input.age,department: input.department}return new Promise((resolve, reject) => {pool.query('insert into accout set ?', data, (err) => {if (err) {console.log('error',err.message);return;}//返回保存结果resolve(data);})})},updateAccount({id,input}) {const data=input;return new Promise((resolve,reject)=>{pool.query('update account set?where name=?',[data,id],(err)=>{if(err){console.log('err',err.message);return;}resolve(data);})})    },deleteAccount({id}){return new Promise((resolve,reject)=>{pool.query('delete account where name=?',[id],(err)=>{if(err){console.log("err",err.message)reject(false);return;}resolve(true);})})}
}
const app = express();
//增加一个判断权限的中间件
const middleware = (req, res, next) => {if (req.url.indexOf('/graphql') != -1 && req.headers.cookie.indexOf('auth')) {res.send(JSON.stringify({error: "您没有权限访问这个接口"}));return;}next();
}
//使用中间件
app.use(middleware)app.use('/graphql', graphqlHTTP({schema: schema,rootValue: root,graphiql: true
}))app.listen(3000)

学习视频:=search&seid=9265460496338796424

本文标签: GraphQL