В этой статье мы рассмотрим весь процесс настройки сервера GraphQL с использованием Node.js и Express. Мы будем использовать промежуточную библиотеку Express, express-graphql, чтобы помочь нам в этом процессе.

Эта статья изначально была опубликована здесь.

Введение

Если вы еще не знакомы с GraphQL и тем, для чего мы его используем, обязательно ознакомьтесь с этой статьей, где мы подробно расскажем о том, что >GraphQL и почему мы должны использовать его в наших приложениях.

Если вы уже знакомы с ним, вы можете проверить статью, в которой мы внедряем Apollo Client с React для подключения к серверу, который мы сейчас создадим.

Репозиторий, содержащий код, представленный в этой статье, можно найти здесь.

Также будет репозиторий, содержащий внешний интерфейс, использующий этот сервер; его можно найти здесь.

Итак, без лишних слов, приступим!

Настройка конфигурации сервера GraphQL

Во-первых, мы можем начать с создания нового каталога, настройки npm с помощью команды npm init, а затем создать наш файл server.js, в котором будет размещаться наш GraphQL сервер.

Как только мы наведем порядок, мы установим следующие библиотеки:

  • express
  • express-graphql
  • graphql
  • cors

Файл server.js должен выглядеть примерно так:

const app = require("express")();
const cors = require('cors');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");

const schema = buildSchema('');
const root = {};

app.use(cors());

app.use(
  "/graphql",
  graphqlHTTP({
    schema,
    rootValue: root,
    graphiql: true,
  })
);

app.listen(8080, () => {
  console.log('GraphQL server running on port 8080');
});

Давайте рассмотрим каждый шаг процесса настройки, чтобы лучше понять, что происходит на самом деле:

  • Во-первых, импортируйте библиотеку express и вызовите основную функцию, которую она экспортирует, чтобы мы могли настроить наш сервер приложений внутри переменной app.
  • Импортируйте основную функцию библиотеки cors, чтобы помочь нам с запуском нашего сервера в другом домене (localhost с другими портами).
  • Импортируйте метод graphqlHTTP из библиотеки express-graphql, чтобы помочь нам с настройкой схемы GraphQL.
  • Импортируйте метод buildSchema из библиотеки graphql, чтобы определить схему данных (к каким данным мы разрешаем доступ клиентам)
  • Определить пока пустую схему данных
  • На данный момент определите пустой корень, но он будет использоваться для определения наших преобразователей или того, как мы выбираем способ обработки данных для отправки клиенту.
  • Настройте CORS без дополнительной настройки.
  • Определите конфигурацию, которую мы будем использовать для конечной точки '/graphql', которая будет использовать ранее определенную схему, объект корневого преобразователя и игровую площадку, которую мы будем использовать для тестирования и взаимодействия с ней. наши данные в визуальной материи.

Чтобы запустить сервер, все, что вам нужно сделать, это выполнить команду node server.js .

Затем вы можете проверить URL-адрес localhost:8080 в своем браузере, и там вы увидите работающую игровую площадку GraphiQL, которая визуально для взаимодействия с вашими данными/схемой.

Это должно выглядеть примерно так:

Определение схемы

Теперь, когда мы полностью настроили GraphQL, давайте рассмотрим заполнение нашей схемы GraphQL некоторыми данными.

Для простоты мы будем работать с некоторыми более базовыми моделями и определим базовые отношения между этими моделями.

У нас будет модель Author и модель Book со следующими схемами:

Как видно из прикрепленных изображений, у нас будет две базовые модели с тремя, соответственно, четырьмя полями, где мы также определим отношение «один ко многим» (у автора может быть много книг) .

Это означает, что автор может написать много книг, а у книги может быть только один автор.

Вот как мы бы определили эти схемы моделей в коде:

const schema = buildSchema(
  `
    type Query {
      authors: [Author]
      books: [Book] 
    }

    type Author {
      id: String
      firstName: String!
      lastName: String!
      books: [Book]
    }
    type Book {
      id: String
      title: String!
      author: Author
    }
  `
);

Нам также нужно будет определить наш родительский тип Query, в котором размещаются все запросы, извлекающие данные. После определения родительского запроса нам нужно определить схемы для моделей Author и Book.

Вы можете заметить знак «!» после некоторых типов полей, который означает, что поле не может быть пустым. Квадратные скобки ('[]') вокруг типа означают, что это массив.

Издевательство над нашими данными

Теперь у нас есть определенная схема, но отсутствуют еще две вещи: данные и преобразователи для разрешения данных в запросах.

Давайте сначала начнем с макетирования наших данных в соответствии со схемой, которую мы ранее определили:

const mockedAuthors = [
  {
    id: '1',
    firstName: "Mike",
    lastName: "Ross",
  },
  {
    id: '2',
    firstName: "John",
    lastName: "Miles",
    books: [
      {
        id: '1',
        title: "Book 1",
        author: {
          id: '2',
          firstName: "John",
          lastName: "Miles",
        },
      },
      {
        id: '2',
        title: "Book 2",
        author: {
          id: '2',
          firstName: "John",
          lastName: "Miles",
        },
      },
    ],
  },
];

const mockedBooks = {
  '1': {
    title: "Book 1",
    author: mockedAuthors["2"],
  },
  '2': {
    title: "Book 2",
    author: mockedAuthors["2"],
  },
};

Как вы могли заметить, Майк Росс еще не написал ни одной книги, и это не проблема, поскольку схема Author не требует никаких книг в своем массиве.

Кроме того, нет необходимости определять массив книг, поскольку это не требуется для схемы.

Однако мы могли бы изменить это, изменив тип поля books с Author на [Book]!, что потребовало бы как минимум массива, пустого или нет.

Определение преобразователей

Теперь, когда у нас есть и схема, и данные, мы можем закончить, определив распознаватели, которые мы будем использовать для обработки того, как мы доставляем эти данные клиенту.

На данный момент нам понадобятся только два преобразователя:

  • Один для разрешения данных авторов
  • Один для разрешения данных книг

Мы определим распознаватели в root следующим образом:

const root = {
  authors: () => mockedAuthors,
  books: () => mockedBooks,
};

Как видно из приведенного выше фрагмента кода, процесс определения преобразователей относительно прост.

Там будет свойство, которое действует как имя запроса, что означает, что, запрашивая конкретно «авторов», все в нижнем регистре, вы получите данные «mockedAuthors».

Обратите внимание, что мы также передаем функции как значения свойствам; это очень важно.

Давайте теперь проверим все, чтобы убедиться, что все работает так, как ожидалось:

Как видите, все работает нормально, как и ожидалось.

Мы используем специальную терминологию GraphQL, упоминая, что делаем запрос, используя ключевое слово 'query', за которым следуют свойства/типы/записи, которые мы хотим запросить.

В этом случае мы хотели запросить все свойства типа Author, но только идентификатор и заголовок для типа Book; мы пропустили поле Автор.

Поскольку мы имитировали данные, чтобы включить авторов в книги, мы могли бы выполнять циклические запросы, такие как этот:

Итак, вот оно. Вы видите, как легко настроить сервер GraphQL и определить для него схему и преобразователи.

Определяя типы, вы не только выполняете проверку, но также можете получить доступ к документации из выбранной вами игровой площадки.

GraphiQL предоставляет небольшое всплывающее меню «Документы» в правом верхнем углу, в котором отображается документация для всех типов, определенных в схеме:

Теперь, когда мы настроили рабочий процесс получения данных с помощью Запросов, мы также рассмотрим, как мы можем изменить существующие данные с помощью Мутаций.

Определение мутаций

В то время как мы используем запросы для извлечения данных, мы используем мутации для создания, изменения или удаления существующих данных.

Предположим, что мы пытаемся создать новую запись об авторе, мы бы сделали это, определив новый родительский тип Mutation, который будет иметь в качестве полей мутации, которые мы могли бы использовать во всей нашей системе.

После этого нам нужно будет определить для этого преобразователь и вуаля! Это почти все, что нам нужно сделать.

Фрагмент кода ниже должен иллюстрировать окончательный файл server.js с возможностью создания новой записи Author:

const app = require("express")();
const cors = require('cors');
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");

const schema = buildSchema(
  `
    type Query {
      authors: [Author]
      books: [Book] 
    }
    type Mutation {
      createAuthor(
        firstName: String!,
        lastName: String!
      ): Author
    }
    type Author {
      id: String
      firstName: String!
      lastName: String!
      books: [Book]
    }
    type Book {
      id: String
      title: String!
      author: Author
    }
  `
);

const mockedAuthors = [
  {
    id: '1',
    firstName: "Mike",
    lastName: "Ross",
  },
  {
    id: '2',
    firstName: "John",
    lastName: "Miles",
    books: [
      {
        id: '1',
        title: "Book 1",
        author: {
          id: '2',
          firstName: "John",
          lastName: "Miles",
        },
      },
      {
        id: '2',
        title: "Book 2",
        author: {
          id: '2',
          firstName: "John",
          lastName: "Miles",
        },
      },
    ],
  },
];

const mockedBooks = {
  '1': {
    title: "Book 1",
    author: mockedAuthors["2"],
  },
  '2': {
    title: "Book 2",
    author: mockedAuthors["2"],
  },
};

const root = {
  authors: () => mockedAuthors,
  books: () => mockedBooks,
  createAuthor: ({ firstName, lastName }) => {
    const id = String(mockedAuthors.length + 1);
    const createdAuthor = {
      id,
      firstName,
      lastName
    };
    mockedAuthors.push(createdAuthor);
    return createdAuthor;
  }
};

app.use(cors());

app.use(
  "/graphql",
  graphqlHTTP({
    schema,
    rootValue: root,
    graphiql: true,
  })
);

app.listen(8080);

Итак, у вас есть это. У вас должен быть работающий GraphQL Server, с которым можно взаимодействовать для получения, изменения или удаления данных.

Вы можете начать изучать разделение преобразователей и типов схем на отдельные каталоги и файлы и объединить их в файл server.js и многое другое; варианты безграничны при рассмотрении масштабирования приложений GraphQL.

В конце концов, это одна из причин, по которой он был создан.

Надеюсь, вам понравилось читать эту статью, и она помогла вам понять основы настройки сервера GraphQL с помощью Node.js и Express. Если вы чувствуете, что я что-то упустил, дайте мне знать в комментариях ниже.

До скорого. Ваше здоровье!

Полезные ресурсы

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord . Заинтересованы в хакинге роста? Ознакомьтесь с разделом Схема.