使用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服務器:
| 12
 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路由:
| 12
 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這幾個對象:
| 12
 
 | const graphql = require('graphql')const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql
 
 | 
然後,我們通過初始化一個新的GraphQLSchema實例,並傳遞一個對象給它,該對象包含一個query屬性。該屬性是一個GraphQLObjectType對象的實例:
| 12
 3
 4
 5
 6
 7
 
 | const schema = new GraphQLSchema({query: new GraphQLObjectType({
 
 }),
 })
 
 module.exports = schema
 
 | 
在這個新對象中,我們必須指定一個name和一個fields屬性。這個fields屬性是一個對象,其中包含我們的schema的每個字段的屬性。在這個例子中,我們設置了一個hello字段:
| 12
 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文件內容:
| 12
 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文件。
這是我們有的:
| 12
 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()構造函數的對象中:
| 12
 3
 4
 5
 6
 
 | app.use('/graphql',
 graphqlHTTP({
 schema: schema,
 })
 )
 
 | 
好的!
我們現在可以測試一下,看看它是否正常工作。我們可以使用GraphiQL,這是一個很好的測試GraphQL API的工具。
它已經安裝好了,要啟用它,我們需要給graphqlHTTP構造函數傳遞另一個屬性:
| 12
 3
 4
 5
 6
 7
 
 | app.use('/graphql',
 graphqlHTTP({
 schema: schema,
 graphiql: true,
 })
 )
 
 | 
現在你運行node app.js,在瀏覽器中訪問http://localhost:3000/graphqlURL,你將看到GraphiQL的頁面:
![]()
你可以測試第一個API調用,傳遞這個查詢:
這是返回結果:
![]()
現在讓我們來構建一個更複雜的schema。
一個具有嵌套類型的schema。
我腦中有一個例子是一個博客文章。
一篇博客文章有標題、描述,還有作者。作者有一個名字。
讓我們來想一下。
首先,我們添加一組文章和作者:
| 12
 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類型,我們需要先引入它:
| 12
 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參數是傳遞給文章對象的參數,然後根據它查找作者數據。我們將其返回。
| 12
 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數組中的數據:
| 12
 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對象的列表。我們必須在頂部引入它:
| 12
 3
 4
 5
 6
 7
 
 | const {GraphQLSchema,
 GraphQLObjectType,
 GraphQLString,
 GraphQLList,
 GraphQLInt,
 } = graphql
 
 | 
這樣就完成了。我們需要將它添加到我們的schema中,我們就完成了:
| 12
 3
 
 | const schema = new GraphQLSchema({query: queryType,
 })
 
 | 
這是完整的代碼:
| 12
 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”]