2017 年 11 月 28 日

GraphQL 伺服器基礎知識:網路層

GraphQL 伺服器的結構與實作(第二部分)。

GraphQL Server Basics

先前的文章中,我們深入探討了 GraphQL 伺服器的內部運作,學習了 GraphQL schema 及其在執行查詢和 mutation 時的基本作用。

雖然我們了解了 GraphQL 伺服器如何使用 GraphQL 引擎執行這些操作,但我們尚未觸及實際的用戶端-伺服器通訊方面:查詢及其回應如何透過網路傳輸的問題。這就是本文的主題!

GraphQL 伺服器可以使用您偏好的任何程式語言實作。本文重點介紹 JavaScript 以及可協助您建置伺服器的可用程式庫,最值得注意的是:express-graphqlapollo-servergraphql-yoga

透過 HTTP 提供 GraphQL 服務

GraphQL 與傳輸層無關

關於 GraphQL,需要理解的關鍵是,它實際上與透過網路傳輸資料的方式無關。這表示 GraphQL 伺服器可能可以使用 HTTP 以外的協定(例如 WebSocket 或更底層的 TCP)運作。但是,本文重點介紹目前實作 GraphQL 伺服器最常見的方式,即以 HTTP 為基礎。

Express.js 用作強大且彈性的基礎

以下章節主要介紹 Express.js 及其 middleware 概念,middleware 用於 express-graphqlapollo-server 等 GraphQL 程式庫。如果您已熟悉 Express,可以跳到下一節。

Comparison of express, hapi, koa and sail on npm trendsexpresshapikoasailnpm trends 上的比較

Express.js 是目前最受歡迎的 JavaScript Web 框架。它以其簡潔性、彈性和效能而著稱。

開始使用您自己的 Web 伺服器所需的所有程式碼如下

使用 Node.js 執行此腳本後,您可以在瀏覽器中存取 https://127.0.0.1:3000 上的網站

您可以輕鬆地將更多端點(也稱為 路由)新增至伺服器的 API

或使用另一個 HTTP 方法,例如 POST 而不是 GET

Express 在實作伺服器方面提供了極大的彈性,讓您可以使用 middleware 的概念輕鬆新增功能。

Express 中彈性和模組化的關鍵:Middleware

Middleware 允許攔截傳入的要求並執行專用任務,同時處理要求或在傳回回應之前執行。

本質上,middleware 只是一個函式,包含三個引數

  • req:來自用戶端的傳入要求
  • res:要傳回給用戶端的回應
  • next:用於調用下一個 middleware 的函式

由於 middleware 函式可以(寫入)存取傳入的要求物件以及傳出的回應物件,因此它們是一個非常強大的概念,可以根據特定目的塑造要求和回應。

Middleware 可以用於許多使用案例,例如驗證快取資料轉換驗證執行自訂業務邏輯等等。以下是一個簡單的記錄範例,它將列印接收到要求的時間

諸如 graphql-expressapollo-servergraphql-yoga 等框架都利用了透過此 middleware 方法獲得的彈性,它們都以 Express 為基礎!

Express & GraphQL

憑藉我們在上一篇文章中學到的所有關於 graphql 函式和 GraphQL 執行引擎的知識,我們已經可以預見基於 Express 的 GraphQL 伺服器如何運作。

由於 Express 提供了處理 HTTP 要求所需的一切,而 GraphQL.js 提供了用於解析查詢的功能,因此我們仍然需要它們之間的橋樑。

此橋樑由 express-graphqlapollo-server 等程式庫提供,它們只是 Express 的 middleware 函式!

GraphQL middleware 將 HTTP 和 GraphQL.js 結合在一起

express-graphql:Facebook 版本的 GraphQL middleware

express-graphql 是 Facebook 版本的 GraphQL middleware,可用於 Express 和 GraphQL.js。如果您查看其原始碼,您會注意到其核心功能僅在幾行程式碼中實作。

實際上,它的主要職責有兩個

  • 確保可以透過 GraphQL.js 執行傳入的 POST 要求主體中包含的 GraphQL 查詢(或 mutation)。因此,它需要剖析查詢並將其轉發到 graphql 函式以執行。
  • 將執行的結果附加到回應物件,以便可以將其傳回給用戶端。

使用 express-graphql,您可以快速啟動 GraphQL 伺服器,如下所示

使用 Node.js 執行此程式碼會在 https://127.0.0.1:4000/graphql 上啟動 GraphQL 伺服器

如果您已閱讀關於 GraphQL schema 的上一篇文章,您將很好地理解第 7 到 18 行的用途:我們建置了一個 GraphQLSchema,可以執行以下查詢

但是,此程式碼片段的新部分是整合的網路層。這次我們不是內嵌編寫查詢並使用 GraphQL.js 直接執行它(如此處所示範),而是設定伺服器以等待傳入的查詢,然後可以針對 GraphQLSchema 執行這些查詢。

您真的不需要更多東西就可以開始使用伺服器端的 GraphQL。

apollo-server:在 Express 生態系統之外具有更好的相容性

本質上,apollo-serverexpress-graphql 非常相似,只有一些細微差異。兩者之間的主要區別在於,apollo-server 也允許與許多其他框架整合,例如 koahapi,以及與 AWS Lambda 或 Azure Functions 等 FaaS 提供者整合。每個整合都可以透過附加套件名稱的對應後綴來安裝,例如 apollo-server-expressapollo-server-koaapollo-server-lambda

但是,在核心部分,它也只是一個 middleware,將 HTTP 層與 GraphQL.js 提供的 GraphQL 引擎橋接起來。以下是使用 apollo-server-express 實作的上述基於 express-graphql 的範例的等效實作

graphql-yoga:建置 GraphQL 伺服器最簡單的方法

消除建置 GraphQL 伺服器時的阻力

即使使用 express-graphqlapollo-server,也存在各種阻力點

  • 需要安裝多個相依性
  • 假設事先了解 Express
  • 使用 GraphQL 訂閱的設定複雜

graphql-yoga 消除了這種阻力,它是一個用於建置 GraphQL 伺服器的簡單程式庫。它本質上是 Express、apollo-server 和一些其他程式庫之上的便利層,旨在提供一種快速建立 GraphQL 伺服器的方法。(可以將其視為 GraphQL 伺服器的 create-react-app。)

以下是我們已經在 express-graphqlapollo-server 中看到的相同 GraphQL 伺服器的外觀

請注意,可以使用 GraphQLSchema 的現成實例或使用便利 API(基於 graphql-tools 中的 makeExecutableSchema)來實例化 GraphQLServer,如上面的程式碼片段所示。

內建支援 GraphQL Playground、訂閱和追蹤

請注意,graphql-yoga 也內建支援 graphql-playground。使用上面的程式碼,您可以在 https://127.0.0.1:4000 開啟 Playground

graphql-yoga 還具有簡單的 API,可用於開箱即用的 GraphQL 訂閱,它建立在 graphql-subscriptionsws-subscriptions-transport 套件之上。您可以在這個簡單明瞭的範例中查看其運作方式。

為了為使用 graphql-yoga 執行的 GraphQL 操作啟用欄位級分析,它還內建支援 Apollo Tracing

結論

在討論了基於 GraphQLSchema 和 GraphQL 引擎(例如 GraphQL.js)概念的 GraphQL 執行過程之後(在上一篇文章中),這次我們重點介紹了網路層。特別是,GraphQL 伺服器如何透過使用執行引擎處理查詢(或 mutation)來回應 HTTP 要求。

在 Node 生態系統中,Express 憑藉其簡潔性和彈性,成為目前建置 Web 伺服器最受歡迎的框架。因此,GraphQL 伺服器最常見的實作是基於 Express,最值得注意的是 express-graphqlapollo-server。這兩個程式庫非常相似,只有一些細微差異,其中最重要的是 apollo-server 也與其他 Web 框架相容,例如 koahapi

graphql-yoga 是許多其他程式庫(例如 graphql-toolsexpressgraphql-subscriptionsgraphql-playground)之上的便利層,也是建置 GraphQL 伺服器最簡單的方法。

在下一篇文章中,我們將討論傳遞到您的 GraphQL 解析器中的 info 引數的內部結構。

不要錯過下一篇文章!

註冊 Prisma 電子報