一、GraphQL 是什么?
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。
一个 GraphQL 服务是通过定义类型和类型上的字段来创建的,然后给每个类型上的每个字段提供解析函数。
二、 简单的使用搭建
1、创建或进入一个空目录,在该目录下输入如下命令
npm init -y
2、搭建环境
npm install express graphql express-graphql -S
3、创建文件 helloworld.js
const express = require('express');
const {buildSchema} = require('graphql');
const { graphqlHTTP } = require('express-graphql');
// 定义schema,查询和类型
const schema = buildSchema(`
type Account {
name: String
age: Int
sex: String
department: String
}
type Query {
hello: String
accountName: String
age: Int
account: Account
}
`)
// 定义查询对应的处理器
const root = {
hello: () => {
return 'hello world';
},
accountName: () => {
return '张三丰';
},
age:()=>{
return 18;
},
account: ()=>{
return {
name: '李四光',
age: 18,
sex: '男',
department: '科学院'
}
}
}
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}))
app.listen(3000, ()=>{
console.log("访问到了");
});
4、运行文件
node helloworld.js
5、浏览器进入 localhost:3000 端口
6、加上后续参数
7、就可以进入 Graphql 界面
三、参数类型与参数传递
1、参数类型
1.1基本类型:String,Int,Float,Boolean和ID,可以在shema声明的时候直接使用
1.2类型 代表数组,例如: [int]代表整型数组
2、参数传递
2.1 和js传递参数一样,小括号定义形参,但是注意:参数需要定义类型
2.2 !(叹号)代表参数不能为空
type Query{
rollDice(numDice:Int!,numSides:Int) :[Int]
}
3、核心代码
const express = require('express');
const {buildSchema} = require('graphql');
const { graphqlHTTP } = require('express-graphql');
const schema = buildSchema(`
type Query {
getClassMates(classNo: Int!): [String]
}
`)
const root = {
getClassMates({ classNo}) {
const obj = {
31: ['张三', '李四', '王五'],
61: ['张大三', '李大四', '王大五']
}
return obj[classNo];
}
}
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}))
app.listen(3000, ()=>{
console.log("访问到了");
});
自定义类型参数
// 定义schema,查询和类型
const schema = buildSchema(`
type Account {
name: String
age: Int
sex: String
department: String
salary(city: String): Int
}
type Query {
getClassMates(classNo: Int!): [String]
account(username: String): Account
}
`)
// 定义查询对应的处理器
const root = {
getClassMates({ classNo}) {
const obj = {
31: ['张三', '李四', '王五'],
61: ['张大三', '李大四', '王大五']
}
return obj[classNo];
},
account({ username}) {
const name = username;
const sex = 'man';
const age = 18;
const department = '开发部';
const salary = ({city}) => {
if(city === "北京" || city == "上海" || city == "广州" || city == "深圳") {
return 10000;
}
return 3000;
}
return {
name,
sex,
age,
department,
salary
}
}
}
四、GraphQL Cli
如何在客户端访问GraphQL?
在baseType.js 追加
app.use(express.static('public'))
在目录下创建public 文件夹,在文件夹下建立 index.html
<!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>
<script>
function getData() {
const query = `
query Account($username: String, $city: String) {
account(username: $username) {
name
age
sex
salary(city: $city)
}
}
`
const variables = {username: '李大四', city: '深圳'}
fetch('/graphql', {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
query: query,
variables: variables
})
}).then(res => res.json())
.then(data => {
console.log(data.data.account);
})
}
</script>
</html>
结果截图
五、使用Mutations修改数据
创建mutation.js
const express = require('express');
const {buildSchema} = require('graphql');
const { graphqlHTTP }= require('express-graphql');
// 定义schema,查询和类型, mutation
const schema = buildSchema(`
input AccountInput {
name: String
age: Int
sex: String
department: String
}
type Account {
name: String
age: Int
sex: String
department: String
}
type Mutation {
createAccount(input: AccountInput): Account
updateAccount(id: ID!, input: AccountInput): Account
}
type Query {
accounts: [Account]
}
`)
const fakeDb = {};
// 定义查询对应的处理器
const root = {
accounts() {
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 updatedAccount = Object.assign({}, fakeDb[id], input);
fakeDb[id] = updatedAccount;
// 返回保存结果
return updatedAccount;
}
}
const app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}))
app.listen(3000,()=>{
console.log("访问到了");
});
六、认证与中间件
const middleware = (req, res, next) => {
if(req.url.indexOf('/graphql') !== -1 && req.headers.cookie.indexOf('auth') === -1) {
res.send(JSON.stringify({
error: "您没有权限访问这个接口"
}));
return;
}
next();
}
app.use(middleware);
七、高级Constructing Types(提高可维护性,代码量上升)
1.使用GraphQLObjectType定义Type(类型)
原始代码
// 定义schema,查询和类型
const schema = buildSchema(`
type Account {
name: String
age: Int
sex: String
department: String
}
type Query {
account(username: String): Account
}
`)
高级代码
var AccountType = new graphql.GraphQLObjectType({
name: 'Account',
fields: {
name: { type: graphql.GraphQLString },
age: { type: graphql.GraphQLInt },
sex: { type: graphql.GraphQLString },
department: { type: graphql.GraphQLString }
}
});
2、使用GraphQLObjectType定义query(查询)
原始代码
const schema = buildSchema(`
type Account {
name: String
age: Int
sex: String
department: String
}
type Query {
account(username: String): Account
}
`)
高级代码
var queryType = new graphql.GraphQLObjectType({
name: 'Query',
fields: {
account: {
type: AccountType,
// `args` describes the arguments that the `user` query accepts
args: {
username: { type: graphql.GraphQLString }
},
resolve: function (_, { username }) {
const name = username;
const sex = 'man';
const age = 18;
const department = '开发部';
return {
name,
sex,
age,
department
}
}
}
}
});
3、创建shema
var schema = new graphql.GraphQLSchema({ query: queryType});