使用Node.js和Express创建GraphQL服务器
這是一個關於如何使用Node.js和Express創建GraphQL服務器的簡單教程。
首先,創建一個新的Node.js項目,如果您還沒有設置一個的話:
這個命令會創建我們使用npm所需的package.json
文件。
安裝npm包express
,graphql
和express-graphql
:
1
| npm install express graphql express-graphql
|
創建一個app.js
文件,並開始初始化Express服務器:
1 2 3 4 5 6 7
| const express = require('express')
const app = express()
app.listen(3000, () => { console.log('App listening on port 3000') })
|
現在我們添加express-graphql
庫,它是一個中間件(middleware),我們將它應用於/graphql
路由:
1 2 3 4 5 6 7 8 9 10
| const express = require('express') const graphqlHTTP = require('express-graphql')
const app = express()
app.use('/graphql', graphqlHTTP())
app.listen(3000, () => { console.log('App listening on port 3000') })
|
我們需要傳遞一個對象,該對象包含了 schema
屬性,該屬性必須包含一個schema定義。
我們首先需要定義一個schema!
創建一個schema.js
文件,然後在其中引入graphql
庫,使用對象解構語法,我們獲取GraphQLSchema
,GraphQLObjectType
和GraphQLString
這幾個對象:
1 2
| const graphql = require('graphql') const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql
|
然後,我們通過初始化一個新的GraphQLSchema
實例,並傳遞一個對象給它,該對象包含一個query
屬性。該屬性是一個GraphQLObjectType
對象的實例:
1 2 3 4 5 6 7
| const schema = new GraphQLSchema({ query: new GraphQLObjectType({ }), })
module.exports = schema
|
在這個新對象中,我們必須指定一個name
和一個fields
屬性。這個fields
屬性是一個對象,其中包含我們的schema的每個字段的屬性。在這個例子中,我們設置了一個hello
字段:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'RootQueryType', fields: { hello: { type: GraphQLString, resolve() { return 'world' }, }, }, }), })
|
resolve()
方法返回字符串world
,這意味著當我們請求hello
字段時,我們將得到這個字符串。
以下是完整的schema.js
文件內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const graphql = require('graphql') const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql
const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: 'RootQueryType', fields: { hello: { type: GraphQLString, resolve() { return 'world' }, }, }, }), })
module.exports = schema
|
現在,讓我們回到我們的app.js
文件。
這是我們有的:
1 2 3 4 5 6 7 8 9 10
| const express = require('express') const graphqlHTTP = require('express-graphql')
const app = express()
app.use('/graphql', graphqlHTTP())
app.listen(3000, () => { console.log('App listening on port 3000') })
|
現在我們需要引入schema.js
文件:
1
| const schema = require('./schema.js')
|
並將其添加到我們傳遞給graphqlHTTP()
構造函數的對象中:
1 2 3 4 5 6
| app.use( '/graphql', graphqlHTTP({ schema: schema, }) )
|
好的!
我們現在可以測試一下,看看它是否正常工作。我們可以使用GraphiQL,這是一個很好的測試GraphQL API的工具。
它已經安裝好了,要啟用它,我們需要給graphqlHTTP
構造函數傳遞另一個屬性:
1 2 3 4 5 6 7
| app.use( '/graphql', graphqlHTTP({ schema: schema, graphiql: true, }) )
|
現在你運行node app.js
,在瀏覽器中訪問http://localhost:3000/graphql
URL,你將看到GraphiQL的頁面:
你可以測試第一個API調用,傳遞這個查詢:
這是返回結果:
現在讓我們來構建一個更複雜的schema。
一個具有嵌套類型的schema。
我腦中有一個例子是一個博客文章。
一篇博客文章有標題、描述,還有作者。作者有一個名字。
讓我們來想一下。
首先,我們添加一組文章和作者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const posts = [ { title: 'First post', description: 'Content of the first post', author: 'Flavio', }, { title: 'Second post', description: 'Content of the second post', author: 'Roger', }, ]
const authors = { Flavio: { name: 'Flavio', age: 36, }, Roger: { name: 'Roger', age: 7, }, }
|
這就是我們將從哪獲取數據。
接下來,我們定義了3個GraphQLObjectType
實例:
authorType
,定義了作者的數據
postType
,定義了文章的數據
queryType
,主要一個
我們先從作者開始。一個作者有名字和年齡。
我們使用了GraphQLInt
類型,我們需要先引入它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInt } = graphql
const authorType = new GraphQLObjectType({ name: 'Author', fields: { name: { type: GraphQLString, }, age: { type: GraphQLInt, }, }, })
|
接下來是postType
。一篇文章有標題和描述(都是字符串),還有一個作者。一個作者是authorType
類型,我們剛剛定義了這個類型,並且它有一個解析器。
我們從source
參數中獲取作者的名字,source
參數是傳遞給文章對象的參數,然後根據它查找作者數據。我們將其返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const postType = new GraphQLObjectType({ name: 'Post', fields: { title: { type: GraphQLString, }, description: { type: GraphQLString, }, author: { type: authorType, resolve: (source, params) => { return authors[source.author] }, }, }, })
|
注意,解析器函數可以是異步的,所以你可以使用async/await從數據庫或者網絡中查詢資源。
接下來是queryType,這是我們將添加到schema中的根類型。在其中,我們定義了2個字段:
post
一篇博客文章,根據id來識別
posts
文章列表
它們都有一個解析器函數來查找在posts
數組中的數據:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const queryType = new GraphQLObjectType({ name: 'Query', fields: { post: { type: postType, args: { id: { type: GraphQLInt }, }, resolve: (source, { id }) => { return posts[id] }, }, posts: { type: new GraphQLList(postType), resolve: () => { return posts }, }, }, })
|
注意到了新的GraphQLList
類型,我們使用它來將postType
包裹起來,表示它是一個postType
對象的列表。我們必須在頂部引入它:
1 2 3 4 5 6 7
| const { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLInt, } = graphql
|
這樣就完成了。我們需要將它添加到我們的schema
中,我們就完成了:
1 2 3
| const schema = new GraphQLSchema({ query: queryType, })
|
這是完整的代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| const graphql = require('graphql') const { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLInt, } = graphql
const posts = [ { title: 'First post', description: 'Content of the first post', author: 'Flavio', }, { title: 'Second post', description: 'Content of the second post', author: 'Roger', }, ]
const authors = { Flavio: { name: 'Flavio', age: 36, }, Roger: { name: 'Roger', age: 7, }, }
const authorType = new GraphQLObjectType({ name: 'Author', fields: { name: { type: GraphQLString, }, age: { type: GraphQLInt, }, }, })
const postType = new GraphQLObjectType({ name: 'Post', fields: { title: { type: GraphQLString, }, description: { type: GraphQLString, }, author: { type: authorType, resolve: (source, params) => { return authors[source.author] }, }, }, })
const queryType = new GraphQLObjectType({ name: 'Query', fields: { post: { type: postType, args: { id: { type: GraphQLInt }, }, resolve: (source, { id }) => { return posts[id] }, }, posts: { type: new GraphQLList(postType), resolve: () => { return posts }, }, }, })
const schema = new GraphQLSchema({ query: queryType, })
module.exports = schema
|
在Glitch上查看完整代碼.
tags: [“GraphQL”, “Node.js”, “Express”, “JavaScript”]