將 REST 包裝為 GraphQL

Mondo 科技 更新 2024-02-01

從前端開發人員的角度來看,GraphQL 是乙個資料層正規化,它支援樂觀更新、React 元件旁邊的宣告性資料獲取和所見即所得資料。 它由 Facebook 推廣,它提供的不僅僅是 RESTful API。 本文附帶乙個來自生產環境的示例,展示了如何在不影響後端開發人員的情況下將現有的 RESTful API 包裝到前端 GraphQL API 中。

在我從外包商那裡接手的乙個前端專案中,我看到了很多有趣的遺物,比如在頁面之間複製和貼上的無用匯入,以及許多帶有 .bak 但是乙個與另乙個頁面沒有太大區別的舊頁面,孩子般的元件命名等。 API 的使用尤其令人印象深刻,如下所示:

import * as mapi from '../../lib/mapi';// ..省略不相關的** componentwillmount() mapipie() then(json => )mapi.whoami() then(json => )
它看起來有點臃腫,因為裡面有很多重複**。

這看起來有點令人困惑,因為我們看不到 piedata 中的內容。 如果你有更深的層次,很容易脫身cannot read property 'machine' of undefinedundefined is not an object,尤其是當您還使用 ES6 計算屬性值時,除錯時間會變得有點長。

還有很多其他問題,例如必須對 UI 中的資料進行非 null 檢查。

這裡的問題是,我們將資料置於一種狀態,該狀態在 null 時不提供型別檢查和預設值,例如 props。

雖然使用 Redux 這樣的資料流框架可以解決大部分問題,但由於現在是重構的時候了,重要的是讓這個重構迭代盡可能長地存在——解決干擾開發人員理解的大問題。 我最感興趣的是資料對我的可見性:

我希望在編寫 UI 時能夠看到資料的樣子,最好資料看起來與我的 UI 結構完全一樣,這樣將資料繫結到 UI 的過程就變得簡單愉快了。 」

現狀是,每次繫結資料都要用郵遞員請求後端看看返回的資料是什麼樣子的,然後呼叫這個API,並從返回的資料中取出一些我需要的資料繫結到UI上,很弱三千取一勺。由於業務變化,我必須同時在乙個 UI 元件中使用多個 API。

我喜歡在常用詞中將字母大寫,例如:deviceid,而後端叔叔喜歡小寫,例如dviceid。哦,我的上帝,他在拼寫時錯過了乙個 e!

理想情況下,後端應該快速跟進業務更改,拆分 API,然後翻閱嬰兒名稱列表,為每個 API 提供乙個新的有意義的名稱。 但顯然後端不會放下手頭的很多東西來配合你改造API,畢竟資料為什麼要跟著UI長一張臉,你覺得你的UI很帥嗎? 此外,如果三天後需求再次發生變化怎麼辦? 讓後端再次重寫其餘的端點,他會用他的皮大衣鞭打你。

同時使用 Redux 和 GraphQL 可以解決這些問題。

過去在REST中,我們根據業務將資料劃分為不同的路徑,相當於根據第乙個版本的業務需求,給每一堆資料乙個當時容易理解的名稱,然後希望以後每個業務都使用乙個

古代外包人員的方法export function whoami() export function pie() export function entry() export function districtpie(id) pie );export function siteoverview(id) /overview`);export function sitepie(id) /pie`);export function cabinetsswitches(id) /cabinets/switches`);export function sitewarningquantity(id) `
在 GraphQL 中,我們將資料表示為一棵樹,並且可以直接請求它的任何葉子。

與REST類似,我們也可以有易於理解的名稱,但是我們可以直接觀察更小粒度的資料,而不是幻想路徑中隱藏了哪些資料,如下所示:

重構的 API 帳戶 WhoamiType UserType API 資訊條目 API 資料站點概述 戰區資訊,指示地球上有哪些據點或子戰區,並且戰區有自己的**比例餅圖資料 它還可以表示據點的資料,其中可以包括比例餅圖和運輸線列表等資料 型別 PowerentityType
我們可以在注釋中看到每個資料型別與原始REST端點之間的關係,乙個資料型別可以從多個原始RESTful資料來源拼湊而成(例如整合多個微服務),或者乙個REST資料來源可以根據常識重組成多個資料型別,這樣三個月後重讀時就可以理解了。

這種轉換有兩個直接的好處:首先,您可以直接看到資料來源的樣子! 不再有郵遞員請求抓取資料,因為你不記得每個資料終結點上有哪些字段可用。 二是它提供了靜態型別檢查,所以你可以在寫型別的時候考慮每個型別應該是什麼樣子,然後把檢查資料可用性的工作放在一邊,專注於業務......

還有兩個間接的好處:乙個是她寫得好像在寫 FlowType 或者 TypeScript,你現在正在給資料新增型別註解,幾個月後你開始學習 Rust 的時候,你會有賓至如歸的感覺,你可以在 21 分鐘內從初學者變成精通。 第二個是可以對資料端點進行標註,可以使用?? 黑色問號運算子宣告性地表達你對業務的困惑,也可以與 ! 划船運算子描述資料項的不可或缺性。

我們上面用來宣告型別的語言叫做 GraphQL,GitHub 正在將他們的 API 遷移到 GraphQL,所以你可以檢查它是如何編寫的。 它通常以模式編寫js 檔案,如下所示:

export const typedefinitions = `schema # ..省略其他型別的宣告
它寫在多行文字第一行內的第一行上,以便更容易檢視除錯的行號。 讓我們將其匯出為常量型別定義。

寫完資料型別宣告後,我們還需要寫架構JS 繼續解釋如何獲取這些資料型別中的每一種以及它們對應的資料。 我們使用分析函式來做到這一點:

// schema.jsexport const resolvers = , args, context) ,username(, args, context) ,password(, args, context) ,token(, args, context) ,id(, args, context) ,name(, args, context) ,companyid(, args, context) ,companyname(, args, context) ,departmentid(, args, context) ,departmentname(, args, context) ,role(, args, context) ,// ..省略其他分析功能,**以實物為準};
正如我們所看到的,我們實際上為每個我們可能需要的字段提供了乙個函式作為資料來源,當我們在 UI 中需要幾個欄位時,我們發出的請求會在這裡觸發一些函式,從而只返回我們需要的字段對應的資料,然後資料會被型別檢查並返回到我們發出請求的 UI。

這可能就是在 UI 中使用它的感覺:

function mapstatetoprops(state) ;const mainpagedata = gql` query mainpagedata($token: string!) const queryconfig = ) => ( 我們配置 GraphQL hoc 在其 props pollinterval: 10000, }props: (=> (connect(mapstatetoprops) Redux classic usage@graphql(MainPageData, QueryConfig) graphql hocexport 預設類 main extends 元件;  static defaultprops = , render()
事實上,graphql 資料端點也是 schemajs 中的資料型別,以及解析函式,應該是後端叔叔寫的。 不過,後台大叔有家庭,有自己的生活,你不應該為了你更開心親自寫UI而要求他放棄生活中的很多美好事物,我們不能這麼殘忍。

更好的方法是插入乙個簡單的 GraphQL 資料端點作為 UI 層和資料層之間的中介。

在這個中介中,我們可以將原本一次性返回一大塊資料的 API 拆分為細粒度的資料型別,可以糾正後端返回的資料中的錯別字,可以檢查資料是否為空,我們來看乙個例子:

// rest2graphqlinterface.以下大部分都是js中的例程,你只需要修改部分模型匯入apolloclient,從'apollo-client';import from 'graphql';import from 'lodash';import from './schemagenerator';import from './schema';import from './models';修改此部分 import houtaidashuconnector from'./houtaidashuconnector';const typedefs = [.rootschema];const resolvers = merge(rootresolvers);const executableschema = makeexecutableschema();const serverconnector = new houtaidashuconnector();const rest2graphqlinterface = ),其中你引入了自己的聯結器 },graphqlrequestvariables );const client = new apolloclient();export default client;
然後將 Redux 提供程式替換為僅限 GraphQL 成員的 ApolloProvider:

從。

成為。

這樣一來,獲取資料的鏈就大致串在一起了,你會發現資料是這樣的:

舅舅後端的 RESTful API ->聯結器 ->模型 ->解析器函式 -ExecutableSchema ->rest2graphqlinterface ->ApolloClient ->redux -> UI 的道具 -> UI

正如我們之前所看到的,當我們建立rest2graphqlinterface時,我們寫道:

user: new user(),
其中 user 是模型。

為什麼會這樣寫?

其實所有的資料採集,也就是請求給後台大叔的RESTful API,我們可以把它放在分析函式裡,但是我們會寫很多重複的**,而且每一點資料我們就要抓一次,這是浪費資源,乙個弱水三千拿一勺喝的概念。

因此,我們抽象出一層模型:

// models.jsexport class user ) async getloginstatus(token) catch (error) async getallmetadata(token) getmetadata(field, token) }
如果我們希望模型專注於資料快取和資料清理,我們必須將網路請求的部分抽象為聯結器:

export default class houtaidashuconnector token=$`;return promise.try(()=> fetch(`$/$$`then(checkstatus) .then(response => response.json())then(json => return json.data; }
這樣一來,我們就可以通過切換聯結器,輕鬆切換我們是連線到內網設定的測試伺服器,還是連線到外網的生產伺服器,而不會影響模型和架構中的邏輯(當然,其實還是會受到影響的,因為你連線了測試伺服器進行更新**以適應最新的業務)。

從那裡,我們在客戶端設定了乙個輕量級的 GraphQL 伺服器,作為我們和後端之間的中介。 基於程序內測試,這對效能沒有明顯影響,良好的快取邏輯甚至可以加快頁面載入速度。

使用此技術後,資料的採集不會寫入componentwillmount()它不是隱藏在 redux reducer 中,不是隱藏在 redux-saga 生成器中,而是真正深入草根,就在我們的 UI 旁邊,愛房子和黑,一石二鳥,所見即所得,腰部柔軟易推。

這種客戶端-graphql-server的方式也非常適合控制物聯網裝置,畢竟在物聯網裝置中設定server-side-graphql-server是不切實際的,使用RESTful API編寫物聯網控制會比較臃腫,在客戶端將這些資料轉換為graphql是一種可行的方法。

如果您對內容有任何疑問,可以新增China GraphQL使用者組302490951進行交流。 比如有個同志看到我之前寫過關於接力的教程,就問我接力好不好,我什麼都知道:不好用,所以現在改用apollostack

wrapping a rest api in graphql apollo-client issue #

相關問題答案

    REST和RPC有什麼區別?

    分布式系統之間的通訊方式對其效率 可靠性和整體功能至關重要。REST 具象狀態傳輸 和RPC 遠端過程呼叫 是眾所周知的通訊正規化。REST 和 RPC 允許不同的系統或元件相互通訊。然而,它們在理念 設計和應用方面有著根本的不同。本教程重點介紹 REST 和 RPC 之間的區別,揭示它們的歷史 原...

    “暖冬,包冬包餃”。

    包餃子 是我國冬至期間許多地方的傳統習,到了月,冬至節的步伐也在慢慢推進。讓精神上感受到相同的文化氛圍是實現健康目標的重要組成部分。為了讓人們與不同的社會群體取得聯絡,增強與他人交往的自信心,進一步促進人們融入社會,在崇州市民政局的指導下,在崇州市精神障礙社群指導中心的支援下,月日,白頭鎮撫遠站與 ...

    我奶奶家包餃子,爺爺因為家太窮而把我打出去

    六七歲那年,家裡忙著種地,父母吃飯不了,有一次我和叔叔的弟弟在外面玩,最後玩累了,餓了,就和弟弟商量去奶奶家吃飯。到了奶奶家,看到奶奶在包餃子,我和弟弟坐在那裡看奶奶包餃子,催奶奶趕緊包餃子,我們都餓死了。奶奶茫然地看了我一眼,說,你是餓鬼轉世!整天,我不幹活,想吃飯回你家吃飯,家裡不欠你吃飯。被奶...

    “神音”把阿音當成免費的血袋?凝水獸的治療技術將被逆轉

    神音 中的仙魔之戰,讓整個三界都吃盡了苦頭,魂獸一族也遭到了毀滅性的打擊,其中凝水獸更是慘不忍睹。仙魔之戰,導致了魂獸種族的瀕臨滅絕,凝水獸的珍貴存在也受到了影響,整個獸族只剩下幾個蛋,阿音的誕生沾染了風音的吉祥之光,可惜她有 卻沒有看到妹妹孵化成功。凝水獸之所以備受推崇,是因為它們蘊含著強大的 能...

    沈音把阿音當成免費的血袋?凝水獸的治療技術將被逆轉

    成像能力計畫 仙魔之戰,三界可以說是吃了不少苦頭,甚至還有不少魂獸被消滅了,凝水獸就是最好的例子,他們的孵化之旅更加艱難,還遭遇了仙魔大戰,最終整個獸族被毀滅到只有兩個蛋,阿音的出生沾染了鳳音的光芒,可惜她已經 很久了,一直沒有看到姐姐孵化成功。凝水獸之所以珍貴,是因為他們體內的能力最強,不管是神還...