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对比
- restful:Representational State Transfer表属性状态转移。本质上就是用定义uri,通过api接口来取得资源。通用系统架构,不受语言限制。restful还是主流。
- 例子:饿了么接口
- restful一个接口只能返回一个资源,graphql一次可以获取多个资源。
- restful用不同的url来区分资源,graphql用类型区分资源。
使用express+GraphQL
- npm init -y //初始化一个package.json文件
- npm i express graphql express-graphql -S
- node helloWorld.js
- localhost:4000/graphql
- 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}
代码
小坑:
- 写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(高级部分)
- 使用GraphQLObjectType定义type(类型)
意义:方便后期维护
- 使用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对比
- restful:Representational State Transfer表属性状态转移。本质上就是用定义uri,通过api接口来取得资源。通用系统架构,不受语言限制。restful还是主流。
- 例子:饿了么接口
- restful一个接口只能返回一个资源,graphql一次可以获取多个资源。
- restful用不同的url来区分资源,graphql用类型区分资源。
使用express+GraphQL
- npm init -y //初始化一个package.json文件
- npm i express graphql express-graphql -S
- node helloWorld.js
- localhost:4000/graphql
- 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}
代码
小坑:
- 写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(高级部分)
- 使用GraphQLObjectType定义type(类型)
意义:方便后期维护
- 使用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】 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/IT/1687132460a67575.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论