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

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

書籍模式:

作者模式
正如你從所附圖片中看到的,我們將有2個(gè)基本模型,分別有3個(gè)和4個(gè)字段,在這里我們也定義了一對(duì)多的關(guān)系。這意味著一個(gè)作者可以寫很多書,而一本書只能有一個(gè)作者。
這就是我們?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ù)的查詢。在定義了父查詢之后,我們將不得不為作者和書的模型定義模式。
你可以注意到一些字段類型后面的"!"符號(hào),這表示一個(gè)字段是不可置空的。方括號(hào)("[]")圍繞著一個(gè)類型,意味著它是一個(gè)數(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 "還沒有寫任何書,這不是一個(gè)問題,因?yàn)樽髡吣J讲恍枰谄鋽?shù)組內(nèi)有任何書。此外,根本不需要定義一個(gè)書的數(shù)組,因?yàn)槟J讲恍枰?。然而,我們可以通過改變作者的書籍字段的類型來改變這種情況。[書籍]!這就要求至少有一個(gè)數(shù)組,不管是不是空的。
定義解析器
現(xiàn)在我們已經(jīng)定義了模式和數(shù)據(jù),我們可以通過定義解析器來完成,我們將使用這些解析器來實(shí)際處理如何將數(shù)據(jù)傳遞給客戶端。
現(xiàn)在,我們只需要兩個(gè)解析器:
- 一個(gè)用于解析作者的數(shù)據(jù)
- 一個(gè)用于解析圖書數(shù)據(jù)
我們將在根中這樣定義解析器:
const root = {
authors: () => mockedAuthors,
books: () => mockedBooks,
};正如你在上面的代碼片段中所看到的,定義解析器的過程是非常直接的。會(huì)有一個(gè)作為查詢名稱的屬性,這意味著通過具體查詢 "author",都是小寫字母,你會(huì)得到 "mockedAuthors "數(shù)據(jù)。
注意,我們還將函數(shù)作為值傳遞給屬性,這一點(diǎn)很關(guān)鍵。
現(xiàn)在讓我們測試一下所有的東西,這樣我們就可以確保它按預(yù)期工作:

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

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

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

