API接口架構(gòu)REST vs GraphQL(api接口和restful接口)
無(wú)論是創(chuàng)建網(wǎng)站,還是移動(dòng)應(yīng)用程序,我們都需要通過 API 來(lái)傳遞數(shù)據(jù),通過 API 我們可以獲取到數(shù)據(jù)庫(kù)中的數(shù)據(jù),可以操作數(shù)據(jù)庫(kù),可以處理一些業(yè)務(wù)邏輯?,F(xiàn)在最流行的 API 架構(gòu)是 REST。但是,GraphQL 正在逐漸追趕著它。
GraphQL 是一種新型的 API 架構(gòu),它比 REST 更靈活、更高效,并且具有聲明式數(shù)據(jù)獲取等功能。雖然 GraphQL 正在變得非常流行,但它并沒有取代 REST,因?yàn)橐恍┯脩舭l(fā)現(xiàn)它更難使用,并認(rèn)為它是一個(gè)過度設(shè)計(jì)的解決方案,尤其是對(duì)于一些小型項(xiàng)目。
REST
現(xiàn)代應(yīng)用程序開發(fā)中 API 的主要架構(gòu)是 REST。大多數(shù)后端框架可以非常容易地實(shí)現(xiàn) REST。REST API 通常通過 HTTP 方法被調(diào)用。通過訪問一個(gè) URL, 就實(shí)現(xiàn)了對(duì)接口的調(diào)用處理。
REST 案例
假設(shè)你正在創(chuàng)建一個(gè)博客站點(diǎn), 在首頁(yè)上,你會(huì)顯示最新文章的摘要,包括標(biāo)題、圖片和簡(jiǎn)短描述。為了提供這些數(shù)據(jù),你需要在后端服務(wù)器上查詢數(shù)據(jù)庫(kù)或者緩存來(lái)獲取結(jié)果。然后一個(gè) REST API 就完成了 GET/api/articles,它以 JSON 數(shù)組的形式返回所需的數(shù)據(jù),如下例所示:
// GET /articles[{"id": 1,"title": "REST is Awesome","image": "https://restblog.com/img/dsh9a89.png","description": "The benefits of REST"},{"id": 2,"title": "How REST Works","image": "https://restblog.com/img/33szad2.png","description": "Learn about REST"}]
REST 的優(yōu)點(diǎn)
方便實(shí)現(xiàn)
在 Web 服務(wù)器應(yīng)用程序中設(shè)置 REST 很簡(jiǎn)單,尤其是當(dāng)我使用一些框架的時(shí)候。比如laravel,express,django,springboot 等,它們都提供了非常方便的方法來(lái)實(shí)現(xiàn) REST 接口。
例如,/api/articles 使用 MongoDB 在 Express 應(yīng)用程序中設(shè)置 REST 接口非常簡(jiǎn)單:
app.get('/api/articles', async (req, res) => {try {const articles = await db.articles.find() res.json(articles)} catch (err) {res.status(500).send(err)}})
通俗易懂
REST 很好理解,基本上通過請(qǐng)求方法和請(qǐng)求參數(shù)還有接口名稱,我們就知道這個(gè)接口的作用,并且無(wú)論是前端人員還是后臺(tái)人員都可以非常容易地通過接口文檔進(jìn)行數(shù)據(jù)的交互。
REST 的缺點(diǎn)
冗余數(shù)據(jù)
回到博客的例子,假設(shè)我們?cè)趧?chuàng)建 PC 站點(diǎn)的同時(shí),也創(chuàng)建了一個(gè)移動(dòng)網(wǎng)站。和桌面版本一樣,在移動(dòng)端的首頁(yè)我們也要顯示文章摘要。由于手機(jī)屏幕尺寸較小,這里的摘要只需要標(biāo)題和圖片,可以省略描述。
但不幸的是,由于/api/articles 接口是固定的,所以移動(dòng)端的 description 在調(diào)用 API 是否仍然會(huì)收到該字段。
這些冗余數(shù)據(jù)在頻繁調(diào)用和發(fā)送大量數(shù)據(jù)的時(shí)候會(huì)造成服務(wù)器的資源浪費(fèi)。
嵌套數(shù)據(jù)
有些時(shí)候我們通過一個(gè)接口要返回更多的數(shù)據(jù)的時(shí)候,我們就會(huì)使用嵌套數(shù)據(jù)。
例如,我們可能需要一個(gè)帶有嵌套評(píng)論的文章。我們?cè)讷@取到文章的時(shí)候,還需要再通過文章id獲取評(píng)論信息。這就會(huì)導(dǎo)致請(qǐng)求時(shí)間的延長(zhǎng)。
GraphQL
REST 數(shù)據(jù)冗余和低效率,促使 Facebook 工程師在 2015 創(chuàng)建了一種新的 API 設(shè)計(jì)模式,稱為 GraphQL。與 REST 一樣,GraphQL 不是特定的軟件,而是 API 設(shè)計(jì)的規(guī)范。
GraphQL 的工作原理
為了了解 GraphQL 的優(yōu)勢(shì),我們將快速概述它的工作原理。與 REST 不同,GraphQL 需要一個(gè)模式來(lái)告訴客戶端和服務(wù)器通過 API 允許哪些數(shù)據(jù)和操作。這些是用 GraphQL 模式是語(yǔ)言定義的,它是一種與語(yǔ)言無(wú)關(guān)的具有強(qiáng)大的類型系統(tǒng)的格式。
GraphQL 例子
讓我們回到獲取文章和評(píng)論的例子中。在我們的 GraphQL 模式中,我們將定義Article類型,該類型具有必需的整數(shù)id字段和用于title、image和可選字符串字段description,如下所示:
type Article { id: Integer! title: String image: String description: String}
除了基本的標(biāo)量類型之外,模式對(duì)象還可以相互引用。我們可以在類型和類型之間創(chuàng)建一對(duì)多的關(guān)系Comment,如下所示:
type Article { id: Integer! title: String image: String description: String comments: [Comment]}type Comment { content: String article: Article author: Author}
定義操作
GraphQL 模式的另一個(gè)重要用途是定義操作,包括讀取數(shù)據(jù)的查詢和寫入數(shù)據(jù)。在這里,我們提供了一個(gè)查詢Articles:
type Article { id: Integer! title: String image: String description: String comments: [Comment]}type Comment { content: String article: Article author: Author}type Query { articles: [Article]}
GraphQL 的優(yōu)點(diǎn)
聲明式數(shù)據(jù)獲取
GraphQL 殺手級(jí)功能是聲明式數(shù)據(jù)獲取,客戶端可以在其中準(zhǔn)確指定它需要的數(shù)據(jù)。這可以包括特定字段,甚至在嵌套對(duì)象中。我們之前看到必須在模式上定義操作。但是,在這些操作中,我們可以指定我們希望查詢返回到模式限制的哪些字段。
例如,我們可以創(chuàng)建一個(gè)查詢,Articles只獲取我們想要的字段,無(wú)論是否嵌套Comments。請(qǐng)參見下面的示例:
query { articles { id title image description comments { content } }}
這是將從該查詢返回的數(shù)據(jù)結(jié)構(gòu)。請(qǐng)注意,在 GraphQL 響應(yīng)中接收到的數(shù)據(jù)將與請(qǐng)求它的查詢具有相同的結(jié)構(gòu)。
{"data": {"articles": [{"id": 1,"title": "REST is Awesome","image": "https://restblog.com/img/dsh9a8.png","description": "An article about REST","comments": [{"content": "GraphQL is better!"}]}}
通過這種方式,GraphQL 消除了冗余數(shù)據(jù)和嵌套數(shù)據(jù)問題。
健壯性
由于強(qiáng)類型和預(yù)定義查詢的要求,GraphQL 可以提供開箱即用的驗(yàn)證和類型檢查。反過來(lái),這意味著 GraphQL 本質(zhì)上是自記錄的。一旦字段、類型或查詢發(fā)生更改,基于架構(gòu)的文檔可以自動(dòng)更新。
沒有版本控制的 API
每次應(yīng)用更改時(shí),API 可能也需要更改。例如,假設(shè)我們決定將實(shí)體中的description字段重命名的時(shí)候.
REST 通過提供多個(gè)版本來(lái)處理這個(gè)問題,這對(duì)于 API 開發(fā)人員來(lái)說(shuō)是很麻煩的。
使用 GraphQL,可以從模式中刪除不推薦使用的字段,而不會(huì)影響現(xiàn)有查詢。這為應(yīng)用程序提供了對(duì)新功能的持續(xù)訪問,并鼓勵(lì)更清潔、更可維護(hù)的代碼。
GraphQL 的缺點(diǎn)
矯枉過正
一些開發(fā)人員認(rèn)為 GraphQL 解決的問題通常被夸大了。例如,對(duì)于大多數(shù)小型應(yīng)用程序來(lái)說(shuō),因?yàn)閹讉€(gè)字節(jié)的冗余數(shù)據(jù)而設(shè)計(jì)的更加復(fù)雜,這可能并不劃算。
難于學(xué)習(xí)
GraphQL 比 REST 更難于實(shí)現(xiàn),它為新用戶提供了更難的學(xué)習(xí)曲線。
難以緩存
GraphQL 經(jīng)常被批評(píng)為更難緩存。REST 客戶端受益于 HTTP 緩存,因?yàn)樗卸它c(diǎn)都是 URL,而 GraphQL 客戶端需要實(shí)現(xiàn)自己的自定義解決方案。
總結(jié)
雖然 REST 架構(gòu)在過去十年中主導(dǎo)了 Web 開發(fā),但它對(duì)接口調(diào)用的的使用使其在某些情況下有些不靈活且效率低下。GraphQL 通過提供嚴(yán)格類型化的模式語(yǔ)言來(lái)解決這些問題,接口調(diào)用者可以根據(jù)自己的需要進(jìn)行查詢。
如果未來(lái)能有更好的設(shè)計(jì)將兩者的優(yōu)點(diǎn)結(jié)合,我相信會(huì)是最佳的解決方案。