GraphQL一個簡單的入門示例

本文首發於 我的博客

目錄

  • 什麼是GraphQL
  • 解決了什麼問題
  • GraphQL一個簡單的入門示例

什麼是GraphQL

官方文檔定義:一種用於API的查詢語言, Graph + Query
有如下特色html

  1. 請求你所要的數據很少很多
  2. 獲取多個資源只用一個請求
  3. 描述全部可能的類型系統

解決了什麼問題

1. 來講一個實際的場景:

先後端聯調接口一直以來都是特別費勁的一個環節,使用REST接口,接口返回的數據格式,數據類型(有哪些字段,字段的類型)都是後端本身預先定義好的,若是返回的數據格式並非調用者所指望的,做爲前端的咱們能夠經過如下兩種方式去解決前端

  • 和後端溝通,該接口(更改數據源)
  • 本身作一些適配工做(處理數據源)

有這種經歷的人都知道,讓後端改接口這是一個很不現實方案,尤爲是對於三端(web、andriod、ios)公用同一套後端接口的狀況下, 讓後端改接口的結構基本不可能,因此通常都是前端本身作一些接口數據的適配工做node

其實咱們真的很但願, 咱們須要什麼數據,須要什麼格式,後端就按照什麼格式給咱們返回什麼樣的數據結構,咱們要哪些字段,後端就只給咱們返回咱們須要的這些字段, 其餘的都不返回,這樣,前端就和後端解耦了,咱們不用再天天和後端由於接口問題去撕逼,GraphQL就是一個這樣的思路來幫助咱們解決這個先後端聯調接口的問題, 在前端直接寫查詢, 後端只管給前端返回前端查詢的這些數據;ios

2. 還有一種場景:

一個頁面裏展現的信息, info1, info2, info3,前端須要請求多個接口,info1對應的接口A中的a字段,info2對應的接口B中的b字段,info3對應的接口C中的c字段git

// /api/user/A
{
    id: 1111,
    name: '張三',
    a: '當前頁面要展現的info1',
    b: 'b'
    // 其餘字段
}
// /api/order/B
{
    id: 2222,
    name: 'hahah',
    a: 'a'
    b: '當前頁面要展現的info2',
    // 其餘字段
}
// /api/system/C
{
    id: 3333,
    name: 'hehe',
    a: 'a'
    c: '當前頁面要展現的info3',
    // 其餘字段
}

這個時候,稍微有點脾氣的前端,都會去找後端撕逼,github

前端A: 「就這三個字段,你還讓我請求三個接口,你不能一個接口都返回給我嗎」,
後端B:「哎, 我也想啊,可是xxxxx, 因此我這邊很差改,」,
...
最後那就這樣吧。web

固然,我舉得這個例子是一個很簡單的場景,實際開發過程當中要比這個還要複雜;express

若是使用GraphQL的話,前端本身寫查詢,這個頁面須要哪些需哪數據,後端就返回給哪些數據,
這是考慮到後端全部的接口都在同一個域下面,可是通常比較複雜的系統,後端都會分爲不一樣的域, 用戶域,商品域,基礎模塊域,交易域等等,這時即便用了GraphQL也可能npm

後端C:「你看其餘都不是我負責的域,我要是本身給你封裝一個,我本身底層須要通過xxxxx等複雜的步驟去獲取其餘域的,這個很複雜, 你仍是直接去他哪一個域去查詢吧」, json

有兩種方法,

  • 你就再多寫一個GraphQL
  • 本身寫一個node中間層,中間層來處理這些接口數據的聚合,換句話說,中間層來聚合成一個GraphQL查詢來返回給前端, 中間層分別取調用服務端的三個接口,而後把三個接口返回的數據聚合成前端所須要的

GraphQL一個簡單的入門示例

準備

npm i --save express  express-graphql graphql cors

服務端代碼

var express = require('express');
var graphqlHTTP = require('express-graphql');
const { buildSchema } = require('graphql');
const cors = require('cors'); // 用來解決跨域問題

// 建立 schema,須要注意到:
// 1. 感嘆號 ! 表明 not-null
// 2. rollDice 接受參數
const schema = buildSchema(`
  type Query {
    username: String
    age: Int!
  }
`)
const root = {
    username: () => {
        return '李華'
    },
    age: () => {
        return Math.ceil(Math.random() * 100)
    },
}
const app = express();
app.use(cors());
app.use('/graphql', graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true
}))

app.listen(3300);
console.log('Running a GraphQL API server at http://localhost:3300/graphql')

客戶端代碼

<!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>graphql demo</title>
</head>

<body>
    <button class="test">獲取當前用戶數據</button>
    <p class="username"></p>
    <p class="age"></p>
</body>
<script>
    var test = document.querySelector('.test');
    test.onclick = function () {
        var username = document.querySelector('.username');
        var age = document.querySelector('.age');
        fetch('http://localhost:3300/graphql', {
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            },
            method: 'POST',
            body: JSON.stringify({
                query: `{
                    username,
                    age,
            }`
            }),
            mode: 'cors' // no-cors, cors, *same-origin
        })
            .then(function (response) {
                return response.json();
            })
            .then(function (res) {
                console.log('返回結果', res);
                username.innerHTML = `姓名:${res.data.username}`;
                age.innerHTML = `年齡:${res.data.age}`
            })
            .catch(err => {
                console.error('錯誤', err);
            });
    }
</script>

</html>

運行結果

graphql

參考

graphql官方文檔
GraphQL 入門介紹

相關文章
相關標籤/搜索