這是一個關於如何使用Node.js和Express創建GraphQL服務器的簡單教程。

首先,創建一個新的Node.js項目,如果您還沒有設置一個的話:

npm init --y

這個命令會創建我們使用npm所需的package.json文件。

安裝npm包expressgraphqlexpress-graphql

npm install express graphql express-graphql

創建一個app.js文件,並開始初始化Express服務器:

const express = require('express')

const app = express()

app.listen(3000, () => {
 console.log('App listening on port 3000')
})

現在我們添加express-graphql庫,它是一個中間件(middleware),我們將它應用於/graphql路由:

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庫,使用對象解構語法,我們獲取GraphQLSchemaGraphQLObjectTypeGraphQLString這幾個對象:

const graphql = require('graphql')
const { GraphQLSchema, GraphQLObjectType, GraphQLString } = graphql

然後,我們通過初始化一個新的GraphQLSchema實例,並傳遞一個對象給它,該對象包含一個query屬性。該屬性是一個GraphQLObjectType對象的實例:

const schema = new GraphQLSchema({
 query: new GraphQLObjectType({
 //...
 }),
})

module.exports = schema

在這個新對象中,我們必須指定一個name和一個fields屬性。這個fields屬性是一個對象,其中包含我們的schema的每個字段的屬性。在這個例子中,我們設置了一個hello字段:

const schema = new GraphQLSchema({
 query: new GraphQLObjectType({
 name: 'RootQueryType',
 fields: {
 hello: {
 type: GraphQLString,
 resolve() {
 return 'world'
 },
 },
 },
 }),
})

resolve()方法返回字符串world,這意味著當我們請求hello字段時,我們將得到這個字符串。

以下是完整的schema.js文件內容:

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文件。

這是我們有的:

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文件:

const schema = require('./schema.js')

並將其添加到我們傳遞給graphqlHTTP()構造函數的對象中:

app.use(
 '/graphql',
 graphqlHTTP({
 schema: schema,
 })
)

好的!

我們現在可以測試一下,看看它是否正常工作。我們可以使用GraphiQL,這是一個很好的測試GraphQL API的工具。

它已經安裝好了,要啟用它,我們需要給graphqlHTTP構造函數傳遞另一個屬性:

app.use(
 '/graphql',
 graphqlHTTP({
 schema: schema,
 graphiql: true,
 })
)

現在你運行node app.js,在瀏覽器中訪問http://localhost:3000/graphqlURL,你將看到GraphiQL的頁面:

你可以測試第一個API調用,傳遞這個查詢:

{
 hello
}

這是返回結果:

現在讓我們來構建一個更複雜的schema。

一個具有嵌套類型的schema。

我腦中有一個例子是一個博客文章。

一篇博客文章有標題、描述,還有作者。作者有一個名字。

讓我們來想一下。

首先,我們添加一組文章和作者:

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類型,我們需要先引入它:

const { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInt } = graphql

//...

const authorType = new GraphQLObjectType({
 name: 'Author',
 fields: {
 name: {
 type: GraphQLString,
 },
 age: {
 type: GraphQLInt,
 },
 },
})

接下來是postType。一篇文章有標題和描述(都是字符串),還有一個作者。一個作者是authorType類型,我們剛剛定義了這個類型,並且它有一個解析器。

我們從source參數中獲取作者的名字,source參數是傳遞給文章對象的參數,然後根據它查找作者數據。我們將其返回。

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數組中的數據:

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對象的列表。我們必須在頂部引入它:

const {
 GraphQLSchema,
 GraphQLObjectType,
 GraphQLString,
 GraphQLList,
 GraphQLInt,
} = graphql

這樣就完成了。我們需要將它添加到我們的schema中,我們就完成了:

const schema = new GraphQLSchema({
 query: queryType,
})

這是完整的代碼:

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上查看完整代碼.