GraphQL圖形可視化

GraphQL——由Facebook創(chuàng)建的接口規(guī)范,用于API的查詢,為前后端數(shù)據(jù)交互提供了新的查詢方式。

一、RESTFul的痛點
1、面對復雜場景的API粒度設計問題

在多端應用開發(fā)需求時,如Web、App、小程序... Web頁面所需的描述字段往往更多一點,為滿足web頁面的接口需求,對于App/小程序而言,接口字段是冗余的,這就造成了流量浪費、產(chǎn)生性能問題~ 同理,為了提高加載速度,通過合并減少請求次數(shù)的方式,也會生成同樣問題。

  • 粗粒度設計
    流量性能浪費:造成移動端不必要的流量損耗;
  • 細粒度設計
    大量接口產(chǎn)生:不同端、不同頁面、不同接口、同一頁面多次請求造成函數(shù)爆炸;
2、API版本規(guī)劃問題

接口字段等可能變動,之類的版本迭代問題

3、雙向通訊的需求

由于http只能由瀏覽器向服務器單向推送消息,如股票等信息實時推送、支付等功能無法實現(xiàn),雖然可以通過websocket實現(xiàn),但不同的通信協(xié)議,接口規(guī)范無法統(tǒng)一表現(xiàn)風格

4、對于組件需要各自管理狀態(tài)的難點

目前程序通常都是通過使用統(tǒng)一狀態(tài)管理工具,對于實現(xiàn)組件各自的狀態(tài)管理這種新的編碼風格相對比較麻煩。

二、三個核心功能及工作方式
  • Queries :提供查詢類接口
  • Mutations: 處理狀態(tài)的變化
  • Subscriptions: 訂閱后端狀態(tài)變化、通知前端
1、Queries功能很類似解構賦值
query {
  hello,
  hi: hello,  // 前端可以通過別名使用
  books(id:'1'),  // 只從books中查找到id為1的數(shù)據(jù)
  books(id:'1'){  // 只從books中查id為1的date、author
    date,
    author
  } 
}

任意字段、對應別名均可自由定制,從而能避免接口版本更新問題,前端不會受后端接口版本變化而影響。

2、Mutations主要處理增刪改邏輯
mutation {
  createBook( name:'創(chuàng)建新書', author:'作者' ) {
    id  // id等其他信息
  }
}
3、Subscriptions前端訂閱后端發(fā)送的消息
subscription{
  subsBooks
}

前端可以自由定制接口,后端可以按需返回,基于websocket實現(xiàn)的。

三、開發(fā)后端程序主要用Apollo Server框架

Apollo Server可以單獨作為服務器,也可以作為Express、Koa的插件被使用。實例基礎:

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

// Schema_gql接口定義
const typeDefs = gql`
    type Query {
        hello: String
    }
`
// 解釋器的實現(xiàn)
const resolvers = {
    Query: {
        hello: ()=>'Hello World'
    }
}
// 創(chuàng)建服務器實例
const server = new ApolloServer({typeDefs,resolvers});
// 啟動
server.listen().then( ({url}) => { console.log('運行會重新啟動playground') } );

詳例開發(fā)圖書的查詢接口:

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 // 是否清空成功
    }
`
// 創(chuàng)建數(shù)據(jù)_Book列表,是一個匿名函數(shù)
const books = ( ()=>{
    Array(6).fill()
    .map( (v,i)=>({
        id: 'book'+i,
        name: 'Name'+i,
        author: 'Author'+i
    }) )
} )();

// 解釋器的實現(xiàn)
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;
        }
    }
}

// 創(chuàng)建服務器實例
const server = new ApolloServer({typeDefs,resolvers});

// 啟動
server.listen().then( ({url}) => { console.log('運行會重新啟動playground') } );

Subscription的用法:

const { PubSub, withFilter} = require('apollo-server');
// PubSub為訂閱發(fā)布模式

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

// 創(chuàng)建訂閱發(fā)布實例
const pubsub = new PubSub();

// 解釋器中添加
const resolvers = {
    Subscripion: {
        subsBooks:{ 
            subscribe: withFilter(
                ( parent, variables ) => pubsub.asyncIterator('UPDATE_BOOK'),
                () => true  // 過濾UPDATE_BOOK消息、發(fā)布true
            )
        }
    },
    // 發(fā)布消息訂閱在Mutation中
    Mutation: {
        createBook: ( parent,args ) => {
            const book = { ...args,id:books.length+1+''};
            books.push(book);
            pubsub.publish('UPDATE_BOOK',{
                subsBooks: true
            })
            return book;
        },
    }
}
四、前端調(diào)用訂閱(示React用法)
import React from 'react';
import { useMutation } from '@/apollo/react-hooks'; // 借用useMutation鉤子實現(xiàn)
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
    }
`

// 創(chuàng)基函數(shù)式組件
function Mutation {
    // 導出create、clear方法,執(zhí)行時會調(diào)用mutation向后端創(chuàng)建數(shù)據(jù)
    const [ create, {data} ] = useMutation(CREATE_BOOK);
    const [ clear ] = useMutation(CLEAR_BOOK);

    // 頁面且放兩個按鈕
    return (
        <div>
            {/* 每次點擊都會創(chuàng)建新數(shù)據(jù) */}
            <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>加載即可

用聲明式數(shù)據(jù)管理取代統(tǒng)一管理的方式,可以使用useSubscription鉤子實現(xiàn)數(shù)據(jù)訂閱,為前后端交互提供新的可能,在每個組件內(nèi)部訂閱數(shù)據(jù)的狀態(tài),寫法更簡單明確、用法更容易~

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容