真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Node.js構(gòu)建GraphQLAPI的方法教程

這篇文章主要講解了“Node.js構(gòu)建GraphQL API的方法教程”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Node.js構(gòu)建GraphQL API的方法教程”吧!

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、云龍ssl等。為千余家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學管理、有技術(shù)的云龍網(wǎng)站制作公司

在傳統(tǒng)的基于REST的API方法中,客戶端發(fā)出請求,而

通過這種新的模式,客戶可以通過縮減響應(yīng)來滿足他們的需求,從而向服務(wù)器進行更高效的查詢。對于單頁應(yīng)用(SPA)或其他前端重度客戶端應(yīng)用,可以通過減少有效載荷大小來加快渲染時間。但是,與任何框架或語言一樣,GraphQL也需要權(quán)衡取舍。在本文中,我們將探討使用GraphQL作為API的查詢語言的利弊,以及如何開始構(gòu)建實現(xiàn)。

為什么選擇GraphQL?

與任何技術(shù)決策一樣,了解GraphQL為你的項目提供了哪些優(yōu)勢是很重要的,而不是簡單地因為它是一個流行詞而選擇它。

考慮一個使用API連接到遠程數(shù)據(jù)庫的SaaS應(yīng)用程序。你想要呈現(xiàn)用戶的個人資料頁面,你可能需要進行一次API GET  調(diào)用,以獲取有關(guān)用戶的信息,例如用戶名或電子郵件。然后,你可能需要進行另一個API調(diào)用以獲取有關(guān)地址的信息,該信息存儲在另一個表中。隨著應(yīng)用程序的發(fā)展,由于其構(gòu)建方式的原因,你可能需要繼續(xù)對不同位置進行更多的API調(diào)用。雖然每一個API調(diào)用都可以異步完成,但你也必須處理它們的響應(yīng),無論是錯誤、網(wǎng)絡(luò)超時,甚至暫停頁面渲染,直到收到所有數(shù)據(jù)。如上所述,這些響應(yīng)的有效載荷可能超過了渲染你當前頁面的需要,而且每個API調(diào)用都有網(wǎng)絡(luò)延遲,總的延遲加起來可能很可觀。

使用GraphQL,你無需進行多個API調(diào)用(例如 GET /user/:id 和 GET /user/:id/addresses  ),而是進行一次API調(diào)用并將查詢提交到單個端點:

query {   user(id: 1) {     name     email     addresses {     street     city     country     }   } }

然后,GraphQL僅提供一個端點來查詢所需的所有域邏輯。如果你的應(yīng)用程序不斷增長,你會發(fā)現(xiàn)自己在你的架構(gòu)中添加了更多的數(shù)據(jù)存儲——PostgreSQL可能是存儲用戶信息的好地方,而redis可能是存儲其他種類信息的好地方——對GraphQL端點的一次調(diào)用將解決所有這些不同的位置,并以他們所請求的數(shù)據(jù)響應(yīng)客戶端。

如果你不確定應(yīng)用程序的需求以及將來如何存儲數(shù)據(jù),則GraphQL在這里也很有用。要修改查詢,你只需添加所需字段的名稱:

addresses {       street +     apartmentNumber   # new information       city       country     }

這極大地簡化了隨著時間的推移而發(fā)展你的應(yīng)用程序的過程。

定義一個GraphQL schema

有各種編程語言的GraphQL服務(wù)器實現(xiàn),但在你開始之前,你需要識別你的業(yè)務(wù)域中的對象,就像任何API一樣。就像REST  API可能會使用JSON模式一樣,GraphQL使用SDL或Schema定義語言來定義它的模式,這是一種描述GraphQL  API可用的所有對象和字段的冪等方式。SDL條目的一般格式如下:

type $OBJECT_TYPE {   $FIELD_NAME($ARGUMENTS): $FIELD_TYPE }

讓我們以前面的例子為基礎(chǔ),定義一下user和address的條目是什么樣子的。

type User {   name:     String   email:    String   addresses:   [Address] }  type Address {   street:   String   city:     String   country:  String }

user 定義了兩個 String 字段,分別是 name 和 email ,它還包括一個稱為 addresses 的字段,它是 Addresses  對象的數(shù)組。Addresses  還定義了它自己的幾個字段。(順便說一下,GraphQL模式不僅有對象,字段和標量類型,還有更多,你也可以合并接口,聯(lián)合和參數(shù),以構(gòu)建更復雜的模型,但本文中不會介紹。)

我們還需要定義一個類型,這是我們GraphQL API的入口點。你還記得,前面我們說過,GraphQL查詢是這樣的:

query {   user(id: 1) {     name     email   } }

該 query 字段屬于一種特殊的保留類型,稱為 Query ,這指定了獲取對象的主要入口點。(還有用于修改對象的 Mutation  類型。)在這里,我們定義了一個 user 字段,該字段返回一個 User 對象,因此我們的架構(gòu)也需要定義此字段:

type Query {   user(id: Int!): User }  type User { ... } type Address { ... }

字段中的參數(shù)是逗號分隔的列表,格式為 $NAME: $TYPE。! 是GraphQL表示該參數(shù)是必需的方式,省略表示它是可選的。

根據(jù)你選擇的語言,將此模式合并到服務(wù)器中的過程會有所不同,但通常,將信息用作字符串就足夠了。Node.js有 graphql[2]  包來準備GraphQL模式,但我們將使用 graphql-tools[3]  包來代替,因為它提供了一些更多的好處。讓我們導入該軟件包并閱讀我們的類型定義,以為將來的開發(fā)做準備:

const fs = require('fs') const { makeExecutableSchema } = require("graphql-tools");  let typeDefs = fs.readFileSync("schema.graphql", {   encoding: "utf8",   flag: "r", });

設(shè)置解析器

schema設(shè)置了構(gòu)建查詢的方式,但建立schema來定義數(shù)據(jù)模型只是GraphQL規(guī)范的一部分。另一部分涉及實際獲取數(shù)據(jù),這是通過使用解析器完成的,解析器是一個返回字段基礎(chǔ)值的函數(shù)。

讓我們看一下如何在Node.js中實現(xiàn)解析器。我們的目的是圍繞著解析器如何與模式一起操作來鞏固概念,所以我們不會圍繞著如何設(shè)置數(shù)據(jù)存儲來做太詳細的介紹。在“現(xiàn)實世界”中,我們可能會使用諸如knex[4]之類的東西建立數(shù)據(jù)庫連接?,F(xiàn)在,讓我們設(shè)置一些虛擬數(shù)據(jù):

const users = {   1: {     name: "Luke",     email: "luke@heroku.space",     addresses: [     {       street: "1234 Rodeo Drive",       city: "Los Angeles",       country: "USA",     },     ],   },   2: {     name: "Jane",     email: "jane@heroku.space",     addresses: [     {       street: "1234 Lincoln Place",       city: "Brooklyn",       country: "USA",     },     ],   }, };

Node.js中的GraphQL解析器相當于一個Object,key是要檢索的字段名,value是返回數(shù)據(jù)的函數(shù)。讓我們從初始 user  按id查找的一個簡單示例開始:

const resolvers = {   Query: {     user: function (parent, { id }) {       // 用戶查找邏輯     },   }, }

這個解析器需要兩個參數(shù):一個代表父的對象(在最初的根查詢中,這個對象通常是未使用的),一個包含傳遞給你的字段的參數(shù)的JSON對象。并非每個字段都具有參數(shù),但是在這種情況下,我們將擁有參數(shù),因為我們需要通過用戶ID來檢索其用戶。該函數(shù)的其余部分很簡單:

const resolvers = {   Query: {     user: function (_, { id }) {       return users[id];     },   } }

你會注意到,我們沒有明確定義 User 或 Addresses 的解析器,graphql-tools  包足夠智能,可以自動為我們映射這些。如果我們選擇的話,我們可以覆蓋這些,但是現(xiàn)在我們已經(jīng)定義了我們的類型定義和解析器,我們可以建立我們完整的模式:

const schema = makeExecutableSchema({ typeDefs, resolvers });

運行服務(wù)器

最后,讓我們來運行這個demo吧!因為我們使用的是Express,所以我們可以使用 express-graphql[5]  包來暴露我們的模式作為端點。該程序包需要兩個參數(shù):schema和根value,它有一個可選參數(shù) graphiql,我們將稍后討論。

使用GraphQL中間件在你喜歡的端口上設(shè)置Express服務(wù)器,如下所示:

const express = require("express"); const express_graphql = require("express-graphql");  const app = express(); app.use(   "/graphql",   express_graphql({     schema: schema,     graphiql: true,   }) ); app.listen(5000, () => console.log("Express is now live at localhost:5000"));

將瀏覽器導航到  http://localhost:5000/graphql,你應(yīng)該會看到一種IDE界面。在左側(cè)窗格中,你可以輸入所需的任何有效GraphQL查詢,而在右側(cè)你將獲得結(jié)果。

這就是 graphiql: true 所提供的:一種方便的方式來測試你的查詢,你可能不想在生產(chǎn)環(huán)境中公開它,但是它使測試變得容易得多。

嘗試輸入上面展示的查詢:

query {   user(id: 1) {     name     email   } }

要探索GraphQL的類型化功能,請嘗試為ID參數(shù)傳遞一個字符串而不是一個整數(shù)。

# 這不起作用 query {   user(id: "1") {     name     email   } }

你甚至可以嘗試請求不存在的字段:

# 這不起作用 query {   user(id: 1) {     name     zodiac   } }

只需用schema表達幾行清晰的代碼,就可以在客戶機和服務(wù)器之間建立強類型的契約。這樣可以防止你的服務(wù)接收虛假數(shù)據(jù),并向請求者清楚地表明錯誤。

性能考量

盡管GraphQL為你解決了很多問題,但它并不能解決構(gòu)建API的所有固有問題。特別是緩存和授權(quán)這兩個方面,只是需要一些預(yù)案來防止性能問題。GraphQL規(guī)范并沒有為實現(xiàn)這兩種方法提供任何指導,這意味著構(gòu)建它們的責任落在了你身上。

緩存

基于REST的API在緩存時不需要過度關(guān)注,因為它們可以構(gòu)建在web的其他部分使用的現(xiàn)有HTTP頭策略之上。GraphQL不具有這些緩存機制,這會對重復請求造成不必要的處理負擔??紤]以下兩個查詢:

query {   user(id: 1) {     name   } }  query {   user(id: 1) {     email   } }

在沒有某種緩存的情況下,只是為了檢索兩個不同的列,會導致兩個數(shù)據(jù)庫查詢來獲取ID為 1 的  User。實際上,由于GraphQL還允許使用別名,因此以下查詢有效,并且還執(zhí)行兩次查找:

query {   one: user(id: 1) {     name   }   two: user(id: 2) {     name   } }

第二個示例暴露了如何批處理查詢的問題。為了快速高效,我們希望GraphQL以盡可能少的往返次數(shù)訪問相同的數(shù)據(jù)庫行。

dataloader[6]程序包旨在解決這兩個問題。給定一個ID數(shù)組,我們將一次性從數(shù)據(jù)庫中獲取所有這些ID;同樣,后續(xù)對同一ID的調(diào)用也將從緩存中獲取該項目。要使用  dataloader 來構(gòu)建這個,我們需要兩樣東西。首先,我們需要一個函數(shù)來加載所有請求的對象。在我們的示例中,看起來像這樣:

const DataLoader = require('dataloader'); const batchGetUserById = async (ids) => {    // 在現(xiàn)實生活中,這將是數(shù)據(jù)庫調(diào)用   return ids.map(id => users[id]); }; // userLoader現(xiàn)在是我們的“批量加載功能” const userLoader = new DataLoader(batchGetUserById);

這樣可以解決批處理的問題。要加載數(shù)據(jù)并使用緩存,我們將使用對 load 方法的調(diào)用來替換之前的數(shù)據(jù)查找,并傳入我們的用戶ID:

const resolvers = {   Query: {     user: function (_, { id }) {       return userLoader.load(id);     },   }, }

授權(quán)

對于GraphQL來說,授權(quán)是一個完全不同的問題。簡而言之,它是識別給定用戶是否有權(quán)查看某些數(shù)據(jù)的過程。我們可以想象一下這樣的場景:經(jīng)過認證的用戶可以執(zhí)行查詢來獲取自己的地址信息,但應(yīng)該無法獲取其他用戶的地址。

為了解決這個問題,我們需要修改解析器函數(shù)。除了字段的參數(shù)外,解析器還可以訪問它的父節(jié)點,以及傳入的特殊上下文值,這些值可以提供有關(guān)當前已認證用戶的信息。因為我們知道地址是一個敏感字段,所以我們需要修改我們的代碼,使對用戶的調(diào)用不只是返回一個地址列表,而是實際調(diào)用一些業(yè)務(wù)邏輯來驗證請求:

const getAddresses = function(currUser, user) {   if (currUser.id == user.id) {     return user.addresses   }    return []; }  const resolvers = {   Query: {     user: function (_, { id }) {       return users[id];     },   },   User: {     addresses: function (parentObj, {}, context) {       return getAddresses(context.currUser, parentObj);     },   }, };

同樣,我們不需要為每個 User 字段顯式定義一個解析程序,只需定義一個我們要修改的解析程序即可。

默認情況下,express-graphql 會將當前的HTTP請求作為上下文的值來傳遞,但在設(shè)置服務(wù)器時可以更改:

app.use(   "/graphql",   express_graphql({     schema: schema,     graphiql: true,     context: {       currUser: user // 當前經(jīng)過身份驗證的用戶     }   }) );

Schema最佳實踐

GraphQL規(guī)范中缺少的一個方面是缺乏對版本控制模式的指導。隨著應(yīng)用程序的成長和變化,它們的API也會隨之變化,很可能需要刪除或修改GraphQL字段和對象。但這個缺點也是積極的:通過仔細設(shè)計你的GraphQL  schema,你可以避免在更容易實現(xiàn)(也更容易破壞)的REST端點中明顯的陷阱,如命名的不一致和混亂的關(guān)系。

此外,你應(yīng)該盡量將業(yè)務(wù)邏輯與解析器邏輯分開。你的業(yè)務(wù)邏輯應(yīng)該是整個應(yīng)用程序的單一事實來源。在解析器中執(zhí)行驗證檢查是很有誘惑力的,但隨著模式的增長,這將成為一種難以維持的策略。

GraphQL什么時候不合適?

GraphQL不能像REST一樣精確地滿足HTTP通信的需求。例如,無論查詢成功與否,GraphQL僅指定一個狀態(tài)碼——200  OK。在這個響應(yīng)中會返回一個特殊的錯誤鍵,供客戶端解析和識別出錯的地方,因此,錯誤處理可能會有些棘手。

同樣,GraphQL只是一個規(guī)范,它不會自動解決你的應(yīng)用程序面臨的每個問題。性能問題不會消失,數(shù)據(jù)庫查詢不會變得更快,總的來說,你需要重新思考關(guān)于你的API的一切:授權(quán)、日志、監(jiān)控、緩存。版本化你的GraphQL  API也可能是一個挑戰(zhàn),因為官方規(guī)范目前不支持處理中斷的變化,這是構(gòu)建任何軟件不可避免的一部分。如果你有興趣探索GraphQL,你需要投入一些時間來學習如何將其與你的需求進行最佳整合。

感謝各位的閱讀,以上就是“Node.js構(gòu)建GraphQL API的方法教程”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Node.js構(gòu)建GraphQL API的方法教程這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!


文章題目:Node.js構(gòu)建GraphQLAPI的方法教程
URL標題:
http://weahome.cn/article/iegjgi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部