GraphQL

一、GraphQL

Facebook产品,跟React一样。

 

 

 描述型的查询语言,可以把我们需要的资源全描述成类型。使用的时候我们可以只取得我们需要的字段。

非常方便的添加和废弃字段。

 按需请求:后台给我提供我需要的字段

 

 

 

 

 前端追求传输数据的Size。按需查询这样特别好。

 二, GraphQL与restful对比

 

 

 

 三、使用express+GraphQL

 

 

graphqlHTTP的参数对象接收三个字段,schema,rootValue和graphiql。我们需要写Schema和处理器。graphiql指定是否启用调试界面。

buildSchema定义查询语句的类型,我们对外公开的接口里面都有哪些查询方法,有哪些类型。

buildSchema的参数是一个字符串。

把执行权交给graphqlHTTP。

 

 

 复杂类型,需要自定义类型。

他可以不请求,但是我需要都返回。

遇到问题,Document一直load不出来,query也出不来提示Query root type must be provided.

原因:定义schema的时候类型Query一定要大写,我写成小写了。

const schema = buildSchema(`
    type Query {
        hello: String
    }
`);

 

 

 四、参数类型和参数传递

GraphQL中基本类型有5种。ID类型,不能重复。

 

 

 

 声明参数类型

 

 

 

 

 

 

 

 

 

 五,GraphQL Client

 

 

 可以看到username是怎样传递给$username的。

客户端传递的query是一个字符串。

 

 

 

 这里的query跟我们调试的时候的query一样。

 

 

子字段也可以接受参数可以通过外面传入。

 

 六,使用Mutations修改数据

 Mutation的英文意思就是修改,变更

输入类型用input定义, input AccountInput

查询类型用type定义。type Account

id: ID!表示id不能为空

定义mutation, 定义输入类型input AccountInput。查询类型Account。

 

 

 对于GraphQL来说,必须有一个query。

 

 

 

 

 

 Input类型

七,认证和中间件

用express框架的中间件,注册中间件

请求/graphql,且请求中有headers,headers中的cookie中没有auth,认为没有权限,返回错误并return终止处理。

const middleware = (req, res, next)=>{
    if(req?.url?.indexOf("/graphql") !== -1 && (req.headers.cookie===undefined || req.headers.cookie?.indexOf("auth") === -1)){
        res.send(JSON.stringify({
            error: "您没有权限访问这个接口"
        }));
        return;
    }
    next();
}
//注册中间件
app.use(middleware); 

实际开发中,服务器会生成token给前端,前端请求再带回来,服务器验证token。

 八、Constructing Types

构造类型,带来我们编程方式的改变。

把类型的定义变成了构造函数。

借助GraphQLObjectType构造函数里面来定义。

代码量上升带来的好处,便于维护。

过去buildSchema一句话完成的事分成了三步,

 

 

 

 

 完整代码

const express = require('express');
const {buildSchema, graphql, GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInt} = require('graphql');
const {graphqlHTTP} = require('express-graphql');

//第一步,定义类型
var AccountType = new GraphQLObjectType({
    name:"Account",
    fields:{
        name:{type: GraphQLString},
        age:{type:GraphQLInt},
        sex:{type:GraphQLString},
        department:{type:GraphQLString}
    }
})

//第二步,定义查询
var queryType = new GraphQLObjectType({
    name:"Query",
    fields:{
        account:{
            type:AccountType,
            args:{
                userName: {type:GraphQLString}
            },
            resolve: (_,{userName})=>{
                const name = userName;
                const sex='man';
                const age=18;
                const department='开发部';
                const salary = ({city})=>{
                    if(city==='北京'|| city ==='上海'|| city==='广州'||city==='深圳'){
                        return 10000;
                    }else{
                        return 3000;
                    }
                }
                return {
                    //属性是无序的
                    name,
                    sex,
                    age,
                    salary,
                    department
                    
                }
            }
        }
    }
})

//第三步,创建Schema
var schema = new GraphQLSchema({query: queryType});

const app = express();
app.use('/graphql', graphqlHTTP({
    schema: schema,
    graphiql: true
    
}))
//公开文件夹,供用户访问静态资源
app.use(express.static('public'))
app.listen(3000);

 九,和db交互

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        : '123456',
  database        : 'alice'
});


//定义schema,定义查询和类型(查询方法), mutation
const schema = buildSchema(`
    type Account{
        name: String,
        age: Int,
        sex: String,
        department: String
    }
    input AccountInput{
        name: String,
        age: Int,
        sex: String,
        department: String
    }
    type Mutation{
        createAccount(input:AccountInput):Account
        updateAccount(id:ID!, input:AccountInput):Account,
        deleteAccount(id:ID!):Boolean
    }
    type Query{
        accounts: [Account]
    }
`);




//定义查询对应的处理器
const root = {
    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 account set ?', data, (err)=>{
                if(err){
                    console.log("出错了",err);
                    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);
                    return;
                }
                resolve(data);
            })
        }); 
    },
    accounts:()=>{
        return new Promise((resolve, reject)=>{
            pool.query('select name, age, sex, department from account',(err, results)=>{
                if(err){
                    console.log("出错了",err);
                    return;
                }
                const arr = [];
                for(let i =0; i<results.length;i++){
                    arr.push({
                        name:results[i].name,
                        age:results[i].age,
                        sex:results[i].sex,
                        department:results[i].department
                    })
                }
                resolve(arr);
            })
        })
    },
    deleteAccount:({id})=>{
        return new Promise((resolve, reject)=>{
            console.log(id);
            pool.query('delete from account where name= ?',[id],(err)=>{
                if(err){
                    console.log("出错了",err);
                    reject(false);
                    return;
                }
                resolve(true);
            })
        });

    }
    
}

const app = express();
app.use('/graphql', graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true
    
}))
//公开文件夹,供用户访问静态资源
app.use(express.static('public'))
app.listen(3000);

 

源码:

https://github.com/starof/qianfeng-graphql

 

posted @ 2021-01-06 08:08  starof  阅读(480)  评论(0编辑  收藏  举报