Как создать сервер GraphQL с помощью Node.js и Express

Простое руководство по созданию сервера GraphQL на базе Node.js и Express

Начните с создания нового проекта Node.js, если вы еще не настроили его:

npm init --y

Эта команда создаетpackage.jsonфайл, с которым нам нужно работатьnpm.

Установите пакеты npmexpress,graphqlиexpress-graphql:

npm install express graphql express-graphql

Создатьapp.jsфайл, и давайте начнем с инициализациивыражатьсервер:

const express = require('express')

const app = express()

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

Теперь добавляемexpress-graphql. Этопромежуточное ПО, и мы применяем его только к маршруту,/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.jsфайл, и здесь мы сначала требуемgraphql, затем с помощьюсинтаксис деструктуризации объектамы получаемGraphQLSchema,GraphQLObjectTypeиGraphQLStringобъекты, которые нам вскоре понадобятся:

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

Затем мы определяем значение схемы, инициализируя новыйGraphQLSchemaэкземпляр, передавая объект, содержащийqueryсвойство. Это свойство является экземпляромGraphQLObjectTypeобъект:

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

module.exports = schema

Внутри этого нового объекта мы должны указатьname, аfieldsпараметры. Это последнее свойство представляет собой объект, который содержит набор свойств, по одному для каждого поля нашей схемы. В этом примере мы настроили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,
  })
)

Ok!

Теперь мы можем проверить это и посмотреть, работает ли оно. Мы можем использоватьGraphiQL, отличный инструмент для тестирования нашего GraphQL API.

Он уже установлен, и для его включения нам нужно передать другое свойство вgraphqlHTTPконструктор:

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

Теперь после того, как ты бежишьnode app.js, доступ кhttp://localhost:3000/graphqlURL-адрес в браузере, вы увидите GraphiQL в действии:

И вы можете протестировать первый вызов API, передав этот запрос:

{
  hello
}

Вот результат:

Давайте теперь построим более сложную схему.

Тот, у которого есть вложенные типы.

В качестве примера я имею в виду сообщение в блоге.

У сообщения в блоге есть заголовок, описание, а также есть автор. У автора есть имя.

Давайте в этом разберемся.

Сначала добавляем набор постов и авторов:

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, }, }

Отсюда мы будем брать данные.

Next, we define 3 GraphQLObjectTypeэкземпляры:

  • authorType, который определяет данные автора
  • postType, который определяет данные записи
  • queryType, главный

Начнем с автора. У автора есть имя и возраст.

Мы используемGraphQLInttype, который мы должны добавить к требованию:

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

//… const authorType = new GraphQLObjectType({ name: ‘Author’, fields: { name: { type: GraphQLString, }, age: { type: GraphQLInt, }, }, })

Далее идетpostType. У сообщения есть заголовок, описание (обе строки) и автор. Автор типаauthorType, который мы только что определили, и у него есть преобразователь.

Имя автора получается из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, корневой тип, который мы добавим в схему. Там мы определяем 2 поля:

  • postодно сообщение в блоге, идентифицируемое по идентификатору
  • 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.


Больше руководств по graphql: