使用 Node 構建 GraphQL API

已發表: 2022-12-20

GraphQL 是 API 開發中的新流行語。 雖然 RESTful API 仍然是從應用程序公開數據的最流行方式,但它們具有 GraphQL 旨在解決的許多限制。

GraphQL 是 Facebook 創建的一種查詢語言,於 2015 年轉變為一個開源項目。它提供了一種直觀靈活的語法來描述和訪問 API 中的數據。

本指南將探討如何構建 GraphQL Node.js 項目。 我們將使用 GraphQL 在 Node 的 Express.js Web 框架中構建 Todo 應用程序。

什麼是 GraphQL?

來自官方文檔:“GraphQL 是一種 API 查詢語言,也是一種使用現有數據完成這些查詢的運行時。 GraphQL 為您的 API 中的數據提供了完整且易於理解的描述,使客戶能夠準確地詢問他們需要什麼,僅此而已,隨著時間的推移更容易發展 API,並啟用強大的開發人員工具。”

GraphQL 是一個服務器端運行時,用於使用您為數據定義的類型系統執行查詢。 此外,GraphQL 不依賴於任何特定的數據庫或存儲引擎。 相反,它由您現有的代碼和數據存儲支持。 您可以通過 GraphQL 與 RESTful API 指南詳細比較這些技術。

要創建 GraphQL 服務,您首先要定義架構類型並使用這些類型創建字段。 接下來,您提供一個函數解析器,在客戶端請求數據時在每個字段和類型上執行。

GraphQL 術語

GraphQL 類型系統用於描述可以查詢哪些數據以及可以操作哪些數據。 它是 GraphQL 的核心。 讓我們討論在 GraphQ 中描述和操作數據的不同方式。

類型

GraphQL 對像類型是包含強類型字段的數據模型。 您的模型和 GraphQL 類型之間應該存在一對一的映射。 以下是 GraphQL 類型的示例:

 type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }

查詢

GraphQL 查詢定義了客戶端可以在 GraphQL API 上運行的所有查詢。 您應該定義一個RootQuery ,它將按照約定包含所有現有查詢。

下面我們定義查詢並將其映射到相應的 RESTful API:

 type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }

突變

如果 GraphQL 查詢是GET請求,則突變是操作 GraphQL API 的POSTPUTPATCHDELETE請求。

我們將把所有的突變放在一個單一的RootMutation中來演示:

 type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }

您注意到對UserInputTodoInput等突變使用了-input類型。 始終定義用於創建和更新資源的輸入類型始終是最佳實踐。

您可以像下面這樣定義輸入類型:

 input UserInput { firstname: String! lastname: String email: String! username: String! }

解析器

解析器告訴 GraphQL 在請求每個查詢或變更時要做什麼。 它是一項基本功能,負責執行 CRUD(創建、讀取、更新、刪除)操作、訪問內部 RESTful API 端點或調用微服務來滿足客戶端請求等艱苦工作。

您可以創建一個新的resolvers.js文件並添加以下代碼:

 import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }

圖式

GraphQL 模式是 GraphQL 向世界公開的內容。 因此,類型、查詢和變更將包含在模式中以向世界公開。

下面是如何向世界公開類型、查詢和突變:

 schema { query: RootQuery mutation: RootMutation }

在上面的腳本中,我們包含了我們之前創建的RootQueryRootMutation以向世界公開。

GraphQL 如何與 Nodejs 和 Expressjs 一起工作

GraphQL 為所有主要編程語言提供了一種實現,Node.js 也不例外。 在 GraphQL 官方網站上,有一個 JavaScript 支持部分,還有 GraphQL 的其他實現,可以簡化 GraphQL 的編寫和編碼。

GraphQL Apollo 為 Node.js 和 Express.js 提供了一個實現,使 GraphQL 的入門變得容易。

在下一節中,您將學習如何使用 GraphQL Apollo 在 Nodes.js 和 Express.js 後端框架中創建和開發您的第一個 GraphQL 應用程序。

使用 Express.js 設置 GraphQL

使用 Express.js 構建 GraphQL API 服務器非常容易上手。 在本節中,我們將探討如何構建 GraphQL 服務器。

使用 Express 初始化項目

首先,您需要安裝並設置一個新的 Express.js 項目。

為您的項目創建一個文件夾並使用以下命令安裝 Express.js:

 cd <project-name> && npm init -y npm install express

上面的命令創建一個新的package.json文件並將 Express.js 庫安裝到您的項目中。

接下來,我們將構建我們的項目,如下圖所示。 它將包含針對項目特性的不同模塊,例如用戶、待辦事項等。

graphql-todo 中的文件列表。
graphql-todo 的文件。

初始化 GraphQL

讓我們從安裝 GraphQL Express.js 依賴項開始。 運行以下命令進行安裝:

 npm install apollo-server-express graphql @graphql-tools/schema --save

創建模式和類型

接下來,我們將在 modules 文件夾中創建一個index.js文件並添加以下代碼片段:

 const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;

代碼演練

讓我們完成代碼片段並將其分解:

步驟1

首先,我們導入了所需的庫並創建了默認查詢和突變類型。 query 和 mutation 目前只設置 GraphQL API 的版本。 然而,我們將擴展查詢和變異以包括我們繼續進行的其他模式。

顯示用於導入 GraphQL 和其他擴展的“常量”代碼的命令行界面。
導入 GraphQL 和擴展。
第2步:

然後我們為時間創建了一個新的標量類型,並為上面創建的查詢和變異創建了我們的第一個解析器。 此外,我們還使用makeExecutableEchema函數生成了一個模式。

生成的模式包括我們導入的所有其他模式,並且在我們創建和導入它們時還將包括更多。

為停機和 WordPress 問題苦苦掙扎? Kinsta 是旨在節省您時間的託管解決方案! 查看我們的功能
命令行界面顯示用於創建標量類型和第一個解析器的“const”代碼。
為時間創建標量類型以及我們的第一個解析器。

上面的代碼片段顯示我們將不同的模式導入到 makeExecutableEchema 函數中。 這種方法有助於我們針對複雜性構建應用程序。 接下來,我們將創建導入的 Todo 和 User 模式。

創建待辦事項架構

Todo 模式顯示了應用程序用戶可以執行的簡單 CRUD 操作。 下面是實現 Todo CRUD 操作的模式。

 const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };

代碼演練

讓我們完成代碼片段並將其分解:

步驟1:

首先,我們使用 GraphQL typeinputextend為 Todo 創建了一個模式。 extend關鍵字用於繼承和添加新的查詢和變異到我們上面創建的現有根查詢和變異。

顯示我們的 Todo 腳本架構的命令行界面,包括新輸入。
為我們的 Todo 創建模式。
第2步:

接下來,我們創建了一個解析器,用於在調用特定查詢或突變時檢索正確的數據。

一個命令行界面,顯示為我們的待辦事項創建解析器的代碼。
創建解析器。

有了解析器函數,我們可以為業務邏輯和數據庫操作創建單獨的方法,如create-todo.js示例所示。

在 <code>./mutations</code> 文件夾中創建一個create-user.js文件,並添加業務邏輯以在您的數據庫中創建一個新的 Todo。

 const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };

上面的代碼片段是使用 Sequelize ORM 在我們的數據庫中創建新 Todo 的簡化方法。 您可以了解有關 Sequelize 以及如何使用 Node.js 進行設置的更多信息。

您可以按照相同的步驟根據您的應用程序創建許多模式,或者您可以從 GitHub 克隆整個項目。

接下來,我們將使用 Express.js 設置服務器並使用 GraphQL 和 Node.js 運行新創建的 Todo 應用程序

設置和運行服務器

最後,我們將使用之前安裝的apollo-server-express庫設置我們的服務器並對其進行配置。

apollo-server-express是 Apollo Server for Express.js 的簡單包裝器,推薦使用它是因為它的開發適合 Express.js 開發。

使用我們上面討論的示例,讓我們配置 Express.js 服務器以與新安裝的 apollo-server-express一起工作。

在根目錄中創建一個server.js文件並粘貼以下代碼:

 const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );

在上面的代碼中,您已經成功地為 Todos 和 Users 創建了您的第一個 CRUD GraphQL 服務器。 您可以啟動開發服務器並使用 http://localhost:3000/graphql 訪問 playground。 如果一切順利,您應該會看到以下屏幕:

顯示簡單查詢響應的開發界面。
驗證屏幕。

概括

GraphQL 是 Facebook 支持的現代技術,它簡化了使用 RESTful 架構模式創建大規模 API 所涉及的繁瑣工作。

本指南闡明了 GraphQL 並演示瞭如何使用 Express.js 開發您的第一個 GraphQL API。

讓我們知道您使用 GraphQL 構建了什麼。