GraphQL是API開發中的新流行語。雖然RESTful APIs仍然是暴露應用程式資料的最流行方式,但它們有許多限制,而GraphQL旨在解決這些限制。
GraphQL是由Facebook建立的一種查詢語言,在2015年變成了一個開源專案。它為描述和訪問API中的資料提供了一個直觀和靈活的語法。
本指南將探討如何建立一個GraphQL Node.js專案。我們將使用GraphQL在Node的Express.js網路框架中建立一個Todo應用程式。
什麼是GraphQL?
來自官方文件:”GraphQL是一種用於API的查詢語言,也是用現有資料完成這些查詢的執行時間。GraphQL為你的API中的資料提供了一個完整的、可理解的描述,使客戶有能力準確地詢問他們所需要的東西,而不是更多,使API更容易隨著時間的推移而發展,並啟用強大的開發者工具。”
GraphQL是一個伺服器端的執行時間,用於使用你為你的資料定義的型別系統執行查詢。此外,GraphQL不與任何特定的資料庫或儲存引擎相聯絡。相反,它是由你現有的程式碼和資料儲存支援的。你可以通過GraphQL與RESTful API指南獲得這些技術的詳細比較。
要建立一個GraphQL服務,你首先要定義模式型別,並使用這些型別建立欄位。接下來,你提供一個函式解析器,在客戶端請求資料的時候,在每個欄位和型別上執行。
GraphQL術語
GraphQL型別系統用於描述哪些資料可以被查詢,哪些資料可以被操作。它是GraphQL的核心。讓我們討論一下我們在GraphQ中描述和運算元據的不同方式。
物件型別
GraphQL物件型別是包含強型別欄位的資料模型。在你的模型和GraphQL型別之間應該有一個1對1的對映。下面是一個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的 POST
, PUT
, PATCH
, 和 DELETE
請求。
我們將把所有的突變放在一個單一的 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 }
你注意到在突變中使用了 -input
型別,如 UserInput
, TodoInput
。在建立和更新你的資源時,總是定義輸入型別是最好的做法。
你可以像下面這樣定義輸入型別:
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 }
在上面的指令碼中,我們包含了我們之前建立的 RootQuery
和 RootMutation
,以暴露在世介面前。
GraphQL如何與Node.js和Express.js一起工作?
GraphQL為所有主要的程式語言提供了一個實現,Node.js也不例外。在GraphQL官方網站上,有一個支援JavaScript的部分,同時,還有GraphQL的其他實現,使編寫和編碼變得簡單。
GraphQL Apollo為Node.js和Express.js提供了一個實現,並使GraphQL容易入門。
你將在下一節中學習如何使用GraphQL Apollo在Node.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庫安裝到你的專案中。
接下來,我們將按照下圖所示,構建我們的專案。它將包含專案功能的不同模組,如使用者、todos等。
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步
首先,我們匯入了所需的庫,並建立了預設的查詢和變異型別。查詢和突變目前只設定了GraphQL API的版本。然而,隨著我們的進展,我們將擴充套件查詢和突變以包括其他模式。
匯入GraphQL和擴充套件
第2步:
然後我們為時間建立了一個新的標量型別,併為上面建立的查詢和突變建立了我們的第一個解析器。此外,我們還使用 makeExecutableEchema
函式生成了一個模式。
生成的模式包括我們匯入的所有其他模式,當我們建立和匯入這些模式時,也將包括更多的模式。
為時間建立一個標量型別,以及我們的第一個解析器。
上面的程式碼片段顯示,我們在makeExecutableEchema函式中匯入了不同的模式。這種方法有助於我們在結構化應用程式的複雜性。接下來,我們要建立我們匯入的Todo和User模式。
建立Todo模式
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 type
, input
, 和 extend
為我們的Todo建立一個模式。extend
關鍵字是用來繼承和新增新的查詢和突變到我們上面建立的現有根查詢和突變。
為Todo建立模式
第2步:
接下來,我們建立了一個解析器,用於在呼叫特定查詢或變異時檢索正確的資料。
建立解析器
使用解析器函式,我們可以為業務邏輯和資料庫操作建立單獨的方法,如create-todo.js示例所示。
在 ./mutations
資料夾中建立一個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
是一個用於Express.js的Apollo伺服器的簡單包裝,它被推薦是因為它已經被開發為適合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 來訪問遊樂場。如果一切成功,你應該看到下面的螢幕:
驗證螢幕
小結
GraphQL是由Facebook支援的現代技術,它簡化了使用RESTful架構模式建立大規模API的繁瑣工作。
本指南闡明瞭GraphQL,並演示瞭如何用Express.js開發你的第一個GraphQL API。
請在下面的評論中告訴我們你用GraphQL建立了什麼。
評論留言