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

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

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

Начать курс

Введение в GraphQL API с JavaScript

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

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

Для работы вам потребуется Node.js версии 14 или выше и базовое знание JavaScript. Если вы знакомы с Express.js, Apollo Server покажется вам очень похожим — он также использует middleware и работает с HTTP.

Установка и настройка проекта

Создайте новую директорию и инициализируйте проект:

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

Установите необходимые зависимости:

npm install @apollo/server graphql
npm install nodemon --save-dev

Создайте файл index.js — это будет точка входа в наше приложение.

Базовая структура проекта будет выглядеть так:

graphql-tutorial/
├── node_modules/
├── index.js
├── package.json
└── package-lock.json

Создание первого GraphQL сервера

Начнем с минимального сервера, который возвращает простое сообщение. Откройте index.js и добавьте следующий код:

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// Определяем схему GraphQL
const typeDefs = `#graphql
  type Query {
    hello: String
  }
`;

// Резолвер для запроса hello
const resolvers = {
  Query: {
    hello: () => 'Привет, мир! Это первый GraphQL запрос!',
  },
};

// Создаем экземпляр сервера
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

// Запускаем сервер
const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
});

console.log(`🚀 Сервер запущен на: ${url}`);

Запустите сервер командой node index.js. Откройте браузер и перейдите по адресу http://localhost:4000. Вы увидите интерфейс Apollo Sandbox, где сможете выполнять запросы.

Введите в левой панели:

query {
  hello
}

И нажмите кнопку "Run". В ответ вы получите:

{
  "data": {
    "hello": "Привет, мир! Это первый GraphQL запрос!"
  }
}

Работа с типами данных и сложными запросами

GraphQL позволяет определять собственные типы данных. Создадим модель пользователя и книг для нашего API.

Обновите файл index.js:

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// Определяем типы
const typeDefs = `#graphql
  type Book {
    id: ID!
    title: String!
    author: String!
    publishedYear: Int
  }

  type User {
    id: ID!
    name: String!
    email: String!
    books: [Book]
  }

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

// Тестовые данные
const books = [
  { id: '1', title: 'Гарри Поттер', author: 'Дж.К. Роулинг', publishedYear: 1997 },
  { id: '2', title: 'Властелин колец', author: 'Дж.Р.Р. Толкин', publishedYear: 1954 },
  { id: '3', title: '1984', author: 'Джордж Оруэлл', publishedYear: 1949 },
];

const users = [
  { id: '1', name: 'Иван Иванов', email: 'ivan@example.com', bookIds: ['1', '2'] },
  { id: '2', name: 'Анна Петрова', email: 'anna@example.com', bookIds: ['3'] },
];

// Резолверы
const resolvers = {
  Query: {
    books: () => books,
    book: (_, { id }) => books.find(book => book.id === id),
    users: () => users,
    user: (_, { id }) => users.find(user => user.id === id),
  },
  User: {
    books: (parent) => {
      return books.filter(book => parent.bookIds.includes(book.id));
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
});

console.log(`🚀 Сервер запущен на: ${url}`);

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

query {
  users {
    id
    name
    email
    books {
      title
      author
    }
  }
}

Мутации: изменение данных через GraphQL

Мутации в GraphQL используются для создания, обновления и удаления данных. Добавим возможность добавлять новые книги.

Расширьте схему и резолверы:

// Добавляем в typeDefs
type Mutation {
  addBook(title: String!, author: String!, publishedYear: Int): Book
  deleteBook(id: ID!): Book
}

// Добавляем в resolvers
Mutation: {
  addBook: (_, { title, author, publishedYear }) => {
    const newBook = {
      id: String(books.length + 1),
      title,
      author,
      publishedYear: publishedYear || null,
    };
    books.push(newBook);
    return newBook;
  },
  deleteBook: (_, { id }) => {
    const index = books.findIndex(book => book.id === id);
    if (index === -1) {
      throw new Error('Книга не найдена');
    }
    const deletedBook = books.splice(index, 1)[0];
    return deletedBook;
  },
},

Пример мутации для добавления книги:

mutation {
  addBook(title: "Мастер и Маргарита", author: "Михаил Булгаков", publishedYear: 1967) {
    id
    title
    author
  }
}

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

Фильтрация и пагинация данных

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

Обновите схему:

type Query {
  books(filter: BookFilter, pagination: PaginationInput): [Book]
  # ... оста                

Блоги

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