GraphQL API с JavaScript: пошаговый туториал на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в GraphQL и его преимущества

GraphQL — это язык запросов и среда выполнения для API, разработанный Facebook. В отличие от REST, где вы получаете фиксированные структуры данных, GraphQL позволяет клиенту запрашивать только то, что ему нужно. Это делает API более гибкими и эффективными.

В этом пошаговом туториале мы создадим полноценный GraphQL API на JavaScript с использованием Node.js. Вы научитесь настраивать сервер, определять схемы, обрабатывать запросы и мутации. К концу статьи у вас будет работающий API, готовый к интеграции в любой проект.

1. Настройка проекта и установка зависимостей

Для начала создадим новый проект Node.js и установим необходимые пакеты. Мы будем использовать apollo-server — популярную библиотеку для создания GraphQL серверов.

Шаг 1: Инициализация проекта

mkdir graphql-tutorial
cd graphql-tutorial
npm init -y

Шаг 2: Установка Apollo Server и GraphQL

npm install apollo-server graphql

После установки создадим основной файл index.js, где будет располагаться наш сервер.

2. Создание базового GraphQL сервера

Теперь напишем минимальный сервер, который будет принимать запросы и возвращать ответы. Для этого определим схему (schema) и резолверы (resolvers).

Шаг 1: Определение типа данных

Создадим простой тип Book с полями id, title и author.

const { ApolloServer, gql } = require('apollo-server');

// Схема GraphQL
const typeDefs = gql`
  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book]
    book(id: ID!): Book
  }
`;

// Пример данных (в реальном проекте — база данных)
const books = [
  { id: '1', title: 'Война и мир', author: 'Лев Толстой' },
  { id: '2', title: 'Преступление и наказание', author: 'Фёдор Достоевский' },
  { id: '3', title: 'Мастер и Маргарита', author: 'Михаил Булгаков' }
];

// Резолверы — функции, возвращающие данные
const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args) => books.find(book => book.id === args.id)
  }
};

// Создание сервера
const server = new ApolloServer({ typeDefs, resolvers });

// Запуск сервера
server.listen().then(({ url }) => {
  console.log(`🚀  Сервер готов по адресу: ${url}`);
});

Шаг 2: Запуск и тестирование

Выполните команду node index.js и откройте http://localhost:4000 в браузере. Вы увидите GraphQL Playground — инструмент для тестирования запросов.

Попробуйте выполнить простой запрос:

{
  books {
    title
    author
  }
}

Ответ должен содержать список книг с указанными полями.

3. Добавление мутаций и расширение схемы

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

Шаг 1: Определение мутаций в схеме

const typeDefs = gql`
  type Book {
    id: ID!
    title: String!
    author: String!
  }

  input BookInput {
    title: String!
    author: String!
  }

  type Query {
    books: [Book]
    book(id: ID!): Book
  }

  type Mutation {
    addBook(input: BookInput!): Book
    deleteBook(id: ID!): Book
  }
`;

Шаг 2: Реализация резолверов для мутаций

const resolvers = {
  Query: {
    books: () => books,
    book: (parent, args) => books.find(book => book.id === args.id)
  },
  Mutation: {
    addBook: (parent, args) => {
      const newBook = {
        id: String(books.length + 1),
        title: args.input.title,
        author: args.input.author
      };
      books.push(newBook);
      return newBook;
    },
    deleteBook: (parent, args) => {
      const index = books.findIndex(book => book.id === args.id);
      if (index === -1) return null;
      const deletedBook = books.splice(index, 1)[0];
      return deletedBook;
    }
  }
};

Шаг 3: Тестирование мутаций

Теперь в Playground можно выполнять мутации. Например, чтобы добавить новую книгу:

mutation {
  addBook(input: { title: "Анна Каренина", author: "Лев Толстой" }) {
    id
    title
    author
  }
}

А чтобы удалить книгу по ID:

mutation {
  deleteBook(id: "1") {
    id
    title
  }
}

4. Оптимизация и обработка ошибок

В реальном проекте важно правильно обрабатывать ошибки и структурировать код. Рассмотрим несколько улучшений.

Шаг 1: Кастомные типы ошибок

Apollo Server поддерживает встроенные классы ошибок. Используйте ApolloError для возврата понятных сообщений.

const { ApolloError } = require('apollo-server');

const resolvers = {
  Query: {
    book: (parent, args) => {
      const book = books.find(book => book.id === args.id);
      if (!book) {
        throw new ApolloError('Книга не найдена', 'BOOK_NOT_FOUND');
      }
      return book;
    }
  }
};

Шаг 2: Разделение на модули

Для больших проектов выносите схему и резолверы в отдельные файлы. Структура может выглядеть так:

  • schema.js — определение типов и схемы
  • resolvers/ — папка с резолверами для каждого типа
  • models/ — модели данных (например, для работы с БД)

Шаг 3: Работа с базой данных

Вместо статического массива подключите MongoDB или PostgreSQL. Пример с MongoDB и Mongoose:

const mongoose = require('mongoose');

const bookSchema = new mongoose.Schema({
  title: String,
  author: String
});

const Book = mongoose.model('Book', bookSchema);

const resolvers = {
  Query: {
    books: async () => await Book.find(),
    book: async (parent, args) => await Book.findById(args.id)
  },                

Блоги

Рекомендаций по книгам