教你用Node.js與Express建立一個GraphQL服務(wù)器
前言
在這篇文章中,我們將對使用Node.js和Express建立GraphQL服務(wù)器的整個過程進行演練。我們將使用 Express 的中間件庫express-graphql 來協(xié)助我們完成這一過程。
如果你還不熟悉GraphQL以及我們使用它的目的,請務(wù)必查看這篇文章,我們將深入了解GraphQL是什么以及為什么我們應(yīng)該在我們的應(yīng)用程序中使用它。
如果你已經(jīng)熟悉它了,你可能想看看這篇文章,在這篇文章中我們用React實現(xiàn)了Apollo客戶端來連接到我們現(xiàn)在要創(chuàng)建的服務(wù)器。
包含這篇文章中的代碼的資源庫可以在這里找到。
還有一個包含使用該服務(wù)器的前端的資源庫,可以在這里找到。
所以,不用多說了,讓我們開始吧。
GraphQL服務(wù)器配置設(shè)置
首先,我們可能想先創(chuàng)建一個新的目錄,通過以下命令設(shè)置npm npm init命令,然后創(chuàng)建我們的 server.js文件,該文件將承載我們的GraphQL服務(wù)器。
一旦我們完成了這些,我們就需要安裝以下庫:
- express
- express-graphql
- graphql
- cors
server.js文件看起來應(yīng)該是這樣的:
const app = require("express")();
const cors = require('cors');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
const schema = buildSchema('');
const root = {
};
app.use(cors());
app.use(
"/graphql",
graphqlHTTP({
schema,
rootValue: root,
graphiql: true,
})
);
app.listen(8080, () => {
console.log('GraphQL server running on port 8080');
});讓我們來看看配置過程的每一步,這樣我們就能更好地了解實際發(fā)生的情況:
- 首先導(dǎo)入express并調(diào)用其導(dǎo)出的主函數(shù),這樣我們就可以通過app變量來設(shè)置我們的應(yīng)用服務(wù)器了
- 導(dǎo)入cors庫的主函數(shù),以幫助我們解決在不同域(localhost與不同端口)上運行服務(wù)器的問題
- 從Express-graphql庫中導(dǎo)入graphqlHTTP方法,幫助我們進行配置
- 從graphql庫中導(dǎo)入buildSchema方法來定義數(shù)據(jù)模式(我們允許客戶訪問哪些數(shù)據(jù))。
- 現(xiàn)在定義一個空的數(shù)據(jù)模式
- 現(xiàn)在定義一個空的根,但這將被用來定義我們的 調(diào)解器或者說我們選擇如何處理數(shù)據(jù),以便將其發(fā)送到客戶端。
- 設(shè)置 CORS,不需要額外的配置
- 定義我們將用于**"/graphql "**端點的配置,它將利用我們之前定義的模式、根解析器對象,以及我們將用于測試和與我們的數(shù)據(jù)進行可視化交互的游樂場。
為了啟動服務(wù)器,你所需要做的就是執(zhí)行 node server.js命令。然后你可以在你的瀏覽器中檢查 "localhost:8080",在那里你就可以看到GraphiQL游樂場的運行,這是一種與你的數(shù)據(jù)/架構(gòu)進行交互的可視化方式。
它看起來應(yīng)該是這樣的。

在瀏覽器中運行的GraphiQL
定義模式
現(xiàn)在我們已經(jīng)把GraphQL設(shè)置好了,讓我們看看用一些數(shù)據(jù)來填充我們的GraphQL模式。
為了簡單起見,我們將使用一些更基本的模型,并在這些模型之間定義一個基本關(guān)系。我們將有一個作者模型和一個圖書模型,它們將有以下模式:

書籍模式:

作者模式
正如你從所附圖片中看到的,我們將有2個基本模型,分別有3個和4個字段,在這里我們也定義了一對多的關(guān)系。這意味著一個作者可以寫很多書,而一本書只能有一個作者。
這就是我們?nèi)绾卧诖a中定義這些模型模式:
const schema = buildSchema(
`
type Query {
authors: [Author]
books: [Book]
}
type Author {
id: String
firstName: String!
lastName: String!
books: [Book]
}
type Book {
id: String
title: String!
author: Author
}
`
);我們還必須定義我們的父查詢類型,它承載了所有檢索數(shù)據(jù)的查詢。在定義了父查詢之后,我們將不得不為作者和書的模型定義模式。
你可以注意到一些字段類型后面的"!"符號,這表示一個字段是不可置空的。方括號("[]")圍繞著一個類型,意味著它是一個數(shù)組。
嘲弄我們的數(shù)據(jù)
我們現(xiàn)在已經(jīng)定義了模式,但還缺少兩樣?xùn)|西:數(shù)據(jù)和解析器來解析查詢的數(shù)據(jù)。
首先,讓我們根據(jù)之前定義的模式來模擬我們的數(shù)據(jù):
const mockedAuthors = [
{
id: '1',
firstName: "Mike",
lastName: "Ross",
},
{
id: '2',
firstName: "John",
lastName: "Miles",
books: [
{
id: '1',
title: "Book 1",
author: {
id: '2',
firstName: "John",
lastName: "Miles",
},
},
{
id: '2',
title: "Book 2",
author: {
id: '2',
firstName: "John",
lastName: "Miles",
},
},
],
},
];
const mockedBooks = {
'1': {
title: "Book 1",
author: mockedAuthors["2"],
},
'2': {
title: "Book 2",
author: mockedAuthors["2"],
},
};正如你可能注意到的,"Mike Ross "還沒有寫任何書,這不是一個問題,因為作者模式不需要在其數(shù)組內(nèi)有任何書。此外,根本不需要定義一個書的數(shù)組,因為模式不需要它。然而,我們可以通過改變作者的書籍字段的類型來改變這種情況。[書籍]!這就要求至少有一個數(shù)組,不管是不是空的。
定義解析器
現(xiàn)在我們已經(jīng)定義了模式和數(shù)據(jù),我們可以通過定義解析器來完成,我們將使用這些解析器來實際處理如何將數(shù)據(jù)傳遞給客戶端。
現(xiàn)在,我們只需要兩個解析器:
- 一個用于解析作者的數(shù)據(jù)
- 一個用于解析圖書數(shù)據(jù)
我們將在根中這樣定義解析器:
const root = {
authors: () => mockedAuthors,
books: () => mockedBooks,
};正如你在上面的代碼片段中所看到的,定義解析器的過程是非常直接的。會有一個作為查詢名稱的屬性,這意味著通過具體查詢 "author",都是小寫字母,你會得到 "mockedAuthors "數(shù)據(jù)。
注意,我們還將函數(shù)作為值傳遞給屬性,這一點很關(guān)鍵。
現(xiàn)在讓我們測試一下所有的東西,這樣我們就可以確保它按預(yù)期工作:

正如你所看到的,這一切都像預(yù)期的那樣工作正常。我們使用GraphQL的特定術(shù)語,提到我們正在做一個查詢,使用 "query "關(guān)鍵字,后面是我們希望查詢的屬性/類型/條目。在這種情況下,我們希望查詢作者類型的所有屬性,但只查詢書籍類型的id和標題;我們跳過了作者字段。
因為我們已經(jīng)模擬了數(shù)據(jù),以包括書籍中的作者,我們可能會做像這樣的循環(huán)查詢。

所以,你有了它。你可以看到設(shè)置GraphQL服務(wù)器并為其定義模式和解析器是多么容易。通過定義類型,你不僅有驗證的地方,而且你還可能從你所選擇的游樂場訪問文檔。
GraphiQL提供了一個右上方的小Docs菜單,它可以跳出來,向你展示在模式中定義的所有類型的文檔。

GraphiQL中的GraphQL自我文檔化模式
現(xiàn)在我們已經(jīng)建立了使用查詢檢索數(shù)據(jù)的工作流程,我們還將看看如何使用突變來修改已有的數(shù)據(jù)。
定義突變
當我們使用查詢來檢索數(shù)據(jù)時,我們使用突變來創(chuàng)建、修改或刪除現(xiàn)有數(shù)據(jù)。
假設(shè)我們要創(chuàng)建一個新的作者條目,我們要做的就是定義一個新的父 "突變"類型,該類型將擁有我們在整個系統(tǒng)中可能使用的突變字段。在那之后,我們必須為它定義解析器,然后就可以了。這將是我們需要做的所有事情。
下面的代碼片段應(yīng)該說明最終的server.js文件具有創(chuàng)建一個新的作者條目的能力:
const app = require("express")();
const cors = require('cors');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");
const schema = buildSchema(
`
type Query {
authors: [Author]
books: [Book]
}
type Mutation {
createAuthor(
firstName: String!,
lastName: String!
): Author
}
type Author {
id: String
firstName: String!
lastName: String!
books: [Book]
}
type Book {
id: String
title: String!
author: Author
}
`
);
const mockedAuthors = [
{
id: '1',
firstName: "Mike",
lastName: "Ross",
},
{
id: '2',
firstName: "John",
lastName: "Miles",
books: [
{
id: '1',
title: "Book 1",
author: {
id: '2',
firstName: "John",
lastName: "Miles",
},
},
{
id: '2',
title: "Book 2",
author: {
id: '2',
firstName: "John",
lastName: "Miles",
},
},
],
},
];
const mockedBooks = {
'1': {
title: "Book 1",
author: mockedAuthors["2"],
},
'2': {
title: "Book 2",
author: mockedAuthors["2"],
},
};
const root = {
authors: () => mockedAuthors,
books: () => mockedBooks,
createAuthor: ({ firstName, lastName }) => {
const id = String(mockedAuthors.length + 1);
const createdAuthor = {
id,
firstName,
lastName
};
mockedAuthors.push(createdAuthor);
return createdAuthor;
}
};
app.use(cors());
app.use(
"/graphql",
graphqlHTTP({
schema,
rootValue: root,
graphiql: true,
})
);
app.listen(8080);所以,你有了它。你應(yīng)該有一個工作的GraphQL服務(wù)器,你可以與之互動,以檢索和修改或刪除數(shù)據(jù)。
你可能會選擇開始研究將解析器和模式類型分離到單獨的目錄和文件中,并在server.js文件中聚合它們,還有更多;在考慮擴展GraphQL應(yīng)用程序時,選擇是無窮無盡的。畢竟,這是它被建立的原因之一。
我希望你喜歡閱讀這篇文章,并希望它能幫助你了解使用Node.js和Express設(shè)置GraphQL服務(wù)器的基本原理。
總結(jié)
到此這篇關(guān)于用Node.js與Express建立一個GraphQL服務(wù)器的文章就介紹到這了,更多相關(guān)Node.js和Express建立GraphQL服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Node學(xué)習(xí)筆記:Node.js安裝及環(huán)境配置 史詩級詳細版【含測試與鏡像說明】
這篇文章主要介紹了Node學(xué)習(xí)筆記之Node.js安裝及環(huán)境配置方法,詳細分析了node.js的基本安裝、配置、環(huán)境變量設(shè)置、以及環(huán)境測試與鏡像使用說明,需要的朋友可以參考下2023-05-05
在Nodejs中實現(xiàn)一個緩存系統(tǒng)的方法詳解
在數(shù)據(jù)庫查詢遇到瓶頸時,我們通??梢圆捎镁彺鎭硖嵘樵兯俣?同時緩解數(shù)據(jù)庫壓力,在一些簡單場景中,我們也可以自己實現(xiàn)一個緩存系統(tǒng),避免使用額外的緩存中間件,這篇文章將帶你一步步實現(xiàn)一個完善的緩存系統(tǒng),需要的朋友可以參考下2024-03-03
Node.js基礎(chǔ)入門之緩存區(qū)與文件操作詳解
Node.js是一個基于Chrome?V8引擎的JavaScript運行時。類似于Java中的JRE,.Net中的CLR。本文將詳細為大家介紹Node.js中的緩存區(qū)與文件操作,感興趣的可以了解一下2022-03-03
nodejs使用redis作為緩存介質(zhì)實現(xiàn)的封裝緩存類示例
這篇文章主要介紹了nodejs使用redis作為緩存介質(zhì)實現(xiàn)的封裝緩存類,涉及nodejs操作redis進行緩存設(shè)置相關(guān)操作技巧,需要的朋友可以參考下2018-02-02
基于Express和Multer實現(xiàn)文件本地服務(wù)器文件上傳功能
在現(xiàn)代應(yīng)用程序中,文件上傳功能成為了用戶共享和存儲數(shù)據(jù)的重要途徑,所以本文我們一起來探討文件上傳中間件的重要性,并提供常見的實現(xiàn)方法和相應(yīng)的代碼吧2023-06-06
npm?ERR!?Node.js?v20.11.0錯誤的解決
在使用?npm?進行包管理和構(gòu)建項目的過程中,有時會遇到錯誤信息?npm?ERR!?Node.js?v20.11.0,本文就來介紹一下如何解決,感興趣的可以了解一下2024-02-02
nodejs實現(xiàn)OAuth2.0授權(quán)服務(wù)認證
本篇文章主要介紹了nodejs實現(xiàn)OAuth2.0授權(quán)服務(wù)認證,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
node schedule實現(xiàn)定時任務(wù)的示例代碼
實際工作中,可能會遇到定時清除某個文件夾內(nèi)容,本文主要介紹了node schedule實現(xiàn)定時任務(wù)的示例代碼,具有一定的參考價值,感興趣的可以了解一下2024-08-08

