GraphQL图形可视化

GraphQL——由Facebook创建的接口规范,用于API的查询,为前后端数据交互提供了新的查询方式。

一、RESTFul的痛点
1、面对复杂场景的API粒度设计问题

在多端应用开发需求时,如Web、App、小程序... Web页面所需的描述字段往往更多一点,为满足web页面的接口需求,对于App/小程序而言,接口字段是冗余的,这就造成了流量浪费、产生性能问题~ 同理,为了提高加载速度,通过合并减少请求次数的方式,也会生成同样问题。

  • 粗粒度设计
    流量性能浪费:造成移动端不必要的流量损耗;
  • 细粒度设计
    大量接口产生:不同端、不同页面、不同接口、同一页面多次请求造成函数爆炸;
2、API版本规划问题

接口字段等可能变动,之类的版本迭代问题

3、双向通讯的需求

由于http只能由浏览器向服务器单向推送消息,如股票等信息实时推送、支付等功能无法实现,虽然可以通过websocket实现,但不同的通信协议,接口规范无法统一表现风格

4、对于组件需要各自管理状态的难点

目前程序通常都是通过使用统一状态管理工具,对于实现组件各自的状态管理这种新的编码风格相对比较麻烦。

二、三个核心功能及工作方式
  • Queries :提供查询类接口
  • Mutations: 处理状态的变化
  • Subscriptions: 订阅后端状态变化、通知前端
1、Queries功能很类似解构赋值
query {
  hello,
  hi: hello,  // 前端可以通过别名使用
  books(id:'1'),  // 只从books中查找到id为1的数据
  books(id:'1'){  // 只从books中查id为1的date、author
    date,
    author
  } 
}

任意字段、对应别名均可自由定制,从而能避免接口版本更新问题,前端不会受后端接口版本变化而影响。

2、Mutations主要处理增删改逻辑
mutation {
  createBook( name:'创建新书', author:'作者' ) {
    id  // id等其他信息
  }
}
3、Subscriptions前端订阅后端发送的消息
subscription{
  subsBooks
}

前端可以自由定制接口,后端可以按需返回,基于websocket实现的。

三、开发后端程序主要用Apollo Server框架

Apollo Server可以单独作为服务器,也可以作为Express、Koa的插件被使用。实例基础:

const { ApolloServer,gql } = require('apollo-server');

// Schema_gql接口定义
const typeDefs = gql`
    type Query {
        hello: String
    }
`
// 解释器的实现
const resolvers = {
    Query: {
        hello: ()=>'Hello World'
    }
}
// 创建服务器实例
const server = new ApolloServer({typeDefs,resolvers});
// 启动
server.listen().then( ({url}) => { console.log('运行会重新启动playground') } );

详例开发图书的查询接口:

const { ApolloServer,gql } = require('apollo-server');

// Schema_gql接口定义
const typeDefs = gql`
    type Query {
        book: [Book], // Book为新的自定义类型
        books( id:String ):Book
    }
    type Book {
        id: String,
        name: Sting,
        author: String
    }

    type Mutation {
        createBook( name:String, author:String ): Books!,  // 必须返回
        clearBook: Boolean // 是否清空成功
    }
`
// 创建数据_Book列表,是一个匿名函数
const books = ( ()=>{
    Array(6).fill()
    .map( (v,i)=>({
        id: 'book'+i,
        name: 'Name'+i,
        author: 'Author'+i
    }) )
} )();

// 解释器的实现
const resolvers = {
    Query: {
        // hello: ()=>'Hello World'
        books: ()=> books,
        book: ( parent,{id} )=>{
            return books.find( v=> v.id===i );
        }
    },
    Mutation: {
        createBook: ( parent,args ) => {
            const book = { ...args,id:books.length+1+''};
            books.push(book);
            return book;
        },
        clearBook: () => {
            books.length = 0;
            return true;
        }
    }
}

// 创建服务器实例
const server = new ApolloServer({typeDefs,resolvers});

// 启动
server.listen().then( ({url}) => { console.log('运行会重新启动playground') } );

Subscription的用法:

const { PubSub, withFilter} = require('apollo-server');
// PubSub为订阅发布模式

const typeDefs = gql`
    type Subscription{
        subsBook: Boolean
    }
`

// 创建订阅发布实例
const pubsub = new PubSub();

// 解释器中添加
const resolvers = {
    Subscripion: {
        subsBooks:{ 
            subscribe: withFilter(
                ( parent, variables ) => pubsub.asyncIterator('UPDATE_BOOK'),
                () => true  // 过滤UPDATE_BOOK消息、发布true
            )
        }
    },
    // 发布消息订阅在Mutation中
    Mutation: {
        createBook: ( parent,args ) => {
            const book = { ...args,id:books.length+1+''};
            books.push(book);
            pubsub.publish('UPDATE_BOOK',{
                subsBooks: true
            })
            return book;
        },
    }
}
四、前端调用订阅(示React用法)
import React from 'react';
import { useMutation } from '@/apollo/react-hooks'; // 借用useMutation钩子实现
import { gql } from 'apollo-boost';

// 第一个查询
const CREATE_BOOK = gql`
    mutation CreateBook( $name: String!, $author: String! ){
        createBook( name: $name, author: $author ){
            id,
            name,
            author
        }
    }
`

// 第二个查询
const CLEAR_BOOK = gql`
    mutation {
        clearBook
    }
`

// 创基函数式组件
function Mutation {
    // 导出create、clear方法,执行时会调用mutation向后端创建数据
    const [ create, {data} ] = useMutation(CREATE_BOOK);
    const [ clear ] = useMutation(CLEAR_BOOK);

    // 页面且放两个按钮
    return (
        <div>
            {/* 每次点击都会创建新数据 */}
            <form onSubmit={ e=> {
                e.preventDefault();
                create({
                    variables:{
                        'name': 'Name' + ( Math.random()*100 ).toFixed(),
                        'author': 'Author' + ( Math.random()*100 ).toFixed()
                    }
                })
            } }></form>
            <button onClick = {clear}> Clear </button>
        </div>
    )
}

export default Mutation;
五、使用

引入Mutation控件、<Mutation></Mutation>加载即可

用声明式数据管理取代统一管理的方式,可以使用useSubscription钩子实现数据订阅,为前后端交互提供新的可能,在每个组件内部订阅数据的状态,写法更简单明确、用法更容易~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容