【GraphQL】---GraphQL的基本使用

GraphQL介绍

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

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

例如一个查询请求:

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

结果如下:

{
	“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:String
		age:Int
		sex:String
	}
	type Query{
		hello:String
		accountName:String
		account: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:String
	age:Int
	sex:String
	salary(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: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:['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){
          name
          age
          sex
          salary(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:String
    age:Int
    sex:String
    department:String
    salary:Int
  }
  type Mutation{
  //括号里是形参
    createAccount(input:AccountInput):Account
    updateAccount(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: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{
    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: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{
    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');
// https://www.npmjs.com/package/mysql
var pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'xxxx'
})

//定义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
    deleteAccount(id:ID):Boolean
    updateAccount(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)

学习视频https://www.bilibili.com/video/av46200333?from=search&seid=9265460496338796424

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值