Заощадьте 15% на всіх хостингових послугах

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код: Skills Почати
Рубрики
Виділені сервери

Повний посібник з GraphQL: Створюйте швидші, розумніші API на високопродуктивному хостингу

GraphQL принципово змінив те, як розробники проектують та використовують API. Народжений у командах інженерів Facebook у 2012 році та випущений для спільноти відкритого коду у 2015 році, GraphQL виріс в одну з найбільш широко прийнятих мов запитів API у сучасній веб-розробці. Незалежно від того, чи ви створюєте додаток для чату в реальному часі, інформаційну панель, багату на дані, чи мобільний продукт із суворими обмеженнями пропускної здатності, GraphQL дає вам хірургічний контроль над тим, які саме дані передаються по мережі.

У цьому комплексному посібнику ви дізнаєтесь, що таке GraphQL, чому він перевершує традиційні REST API у багатьох сценаріях, як налаштувати ваш перший сервер GraphQL та як розгорнути його на інфраструктурі, яка може впоратися з вимогами виробничих навантажень.

1. Що таке GraphQL?

GraphQL — це мова запитів з відкритим кодом для API та середовище виконання для виконання цих запитів проти ваших даних. На відміну від REST, який надає фіксований набір кінцевих точок, кожна з яких повертає заздалегідь визначену структуру даних, GraphQL надає одну кінцеву точку, через яку клієнти можуть запитувати саме ті поля та зв’язки, які їм потрібні — ні більше, ні менше.

Цей підхід усуває дві найпостійніші проблеми в дизайні REST API:

  • Надмірне отримання даних — отримання набагато більше даних, ніж насправді потребує клієнт, що призводить до витрати пропускної здатності та часу обробки.
  • Недостатнє отримання даних — отримання занадто мало даних в одному запиті, що змушує клієнта робити кілька подальших викликів для складання повної картини.

За допомогою GraphQL клієнт визначає форму відповіді. Сервер виконує контракт, визначений схемою, а клієнт запитує лише те, що він має намір використовувати.

2. GraphQL vs. REST: Чому це важливо

Розуміння того, коли вибрати GraphQL замість REST — і навпаки — є критичним для прийняття обґрунтованих архітектурних рішень.

ВимірRESTGraphQL
EndpointsМножинні (один на ресурс)Один уніфікований endpoint
Отримання данихФіксована структура відповідіПоля, вказані клієнтом
Over-fetchingПоширенийУсунений за дизайном
Under-fetchingПоширений (проблема N+1)Вирішений вкладеними запитами
ВерсіонуванняВерсіонування в URL або заголовкуЕволюція схеми без версіонування
Підтримка реального часуВимагає WebSockets або pollingВбудовані підписки
Система типівОпціональна (OpenAPI/Swagger)Вбудована, обов’язкова схема
КешуванняHTTP-рівневе кешування прямолінійнеВимагає кешування з урахуванням запиту

GraphQL особливо потужний для:

  • Складних, взаємопов’язаних моделей даних, де один вид потребує даних з кількох ресурсів.
  • Мобільних додатків, де мінімізація розміру корисного навантаження безпосередньо покращує користувацький досвід і зменшує витрати на дані.
  • Швидкої ітерації продукту, де команди frontend потребують розвивати свої вимоги до даних без очікування змін API backend.
  • Агрегації мікросервісів, де GraphQL gateway об’єднує кілька downstream сервісів в уніфіковану поверхню API.

REST залишається надійним вибором для простих CRUD API, публічних API, які споживаються третіми сторонами, які отримують користь від передбачуваної семантики HTTP, і сценаріїв, де HTTP-рівневе кешування є жорсткою вимогою.

3. Ключові особливості GraphQL

3.1 Точне отримання даних

Визначальною характеристикою GraphQL є те, що клієнти декларують свої вимоги до даних у самому запиті. Один запит до одної кінцевої точки може отримати глибоко вкладений граф пов’язаних об’єктів, з тільки тими полями, які вказав клієнт, заповненими у відповіді.

Це трансформаційно для команд, які розробляють продукти на кількох платформах — веб, iOS, Android, смарт-ТВ — де кожна поверхня має різні потреби в даних. Замість того, щоб підтримувати окремі REST кінцеві точки або приймати перевантажені корисні навантаження, кожен клієнт надсилає адаптований запит і отримує адаптовану відповідь.

3.2 Сильно типізована схема

Кожен GraphQL API підтримується схемою, написаною на мові визначення схеми GraphQL (SDL). Схема є авторитетним контрактом між сервером і кожним клієнтом, який його використовує. Вона визначає:

  • Типи — форму кожного об’єкта у вашій моделі даних.
  • Запити — операції читання, які можуть виконувати клієнти.
  • Мутації — операції запису (створення, оновлення, видалення).
  • Підписки — потоки подій у реальному часі.
  • Відносини — як типи посилаються один на одного.

Оскільки схема сильно типізована, цілі категорії помилок виявляються під час розробки, а не у виробництві. Інструменти можуть перевіряти запити проти схеми перед їх виконанням, а IDE можуть надавати точне автозаповнення та вбудовану документацію.

3.3 Оновлення в реальному часі з підписками

Механізм підписки GraphQL дозволяє постійні, керовані подіями з’єднання між клієнтом і сервером — зазвичай реалізовані через WebSockets. Коли на сервері відбувається подія, на яку підписано (опублікована нова повідомлення, змінюється ціна акції, оновлюється статус замовлення), сервер негайно надсилає відповідні дані всім підписаним клієнтам.

Це робить GraphQL природним вибором для:

  • Додатків живого чату та обміну повідомленнями
  • Інструментів спільного редагування
  • Фінансових панелей з даними живого ринку
  • Сповіщень у реальному часі та стрічок активності
  • Синхронізації стану багатокористувацької гри

3.4 Самоаналіз

GraphQL API самодокументуються за дизайном. Система самоаналізу дозволяє клієнтам запитувати саму схему — виявляючи доступні типи, поля, запити, мутації та їх описи під час виконання. Ця можливість живить інструменти розробника, такі як GraphiQL та Apollo Studio, які надають інтерактивні дослідники API, конструктори запитів та автоматичне генерування документації без будь-яких додаткових зусиль від автора API.

3.5 Еволюція схеми без версіонування

Одним з найбільш практично цінних аспектів GraphQL є те, як він витончено обробляє зміни. Оскільки клієнти запитують тільки поля, які їм потрібні, ви можете додавати нові поля та типи до схеми без порушення існуючих клієнтів. Застарілість старих полів обробляється через анотації схеми, а не через версіонування URL, зберігаючи вашу поверхню API чистою та ваших клієнтів стабільними.

4. Налаштування GraphQL сервера

GraphQL не залежить від мови програмування. Зрілі бібліотеки серверів існують у всьому технологічному стеку. Ось найбільш широко використовувані варіанти:

Мова / RuntimeБібліотека / Фреймворк
Node.jsApollo Server, GraphQL Yoga, Express-GraphQL
PythonStrawberry, Graphene
JavaSpring for GraphQL, graphql-java
Gogqlgen, graphql-go
Rubygraphql-ruby
PHPLighthouse (Laravel), webonyx/graphql-php
Rustasync-graphql
.NET / C#Hot Chocolate, GraphQL.NET

Покроково: Node.js з Apollo Server

Apollo Server — це найбільш широко розгорнутий GraphQL сервер в екосистемі Node.js. Наступний посібник допоможе вам перейти від нуля до запущеного сервера.

Передумови:

  • Node.js 18 або пізніша версія встановлена
  • npm або yarn менеджер пакетів

Крок 1: Ініціалізуйте ваш проект

mkdir graphql-api && cd graphql-api
npm init -y
npm install @apollo/server graphql

Крок 2: Створіть файл сервера

Створіть файл з назвою index.js (або index.mjs для ES модулів):

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

// Step 1: Define your type definitions (schema)
const typeDefs = `#graphql
  type Book {
    id: ID!
    title: String!
    author: String!
    publishedYear: Int
    genre: String
  }

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

// Step 2: Define your data source (in-memory for this example)
const books = [
  {
    id: '1',
    title: 'The Pragmatic Programmer',
    author: 'David Thomas & Andrew Hunt',
    publishedYear: 1999,
    genre: 'Technology',
  },
  {
    id: '2',
    title: 'Clean Code',
    author: 'Robert C. Martin',
    publishedYear: 2008,
    genre: 'Technology',
  },
];

// Step 3: Define your resolvers
const resolvers = {
  Query: {
    books: () => books,
    book: (_, { id }) => books.find((b) => b.id === id),
  },
};

// Step 4: Create and start the server
const server = new ApolloServer({ typeDefs, resolvers });

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

console.log(`🚀 GraphQL server ready at: ${url}`);

Крок 3: Запустіть сервер

node index.js
# Output: 🚀 GraphQL server ready at: http://localhost:4000/

Перейдіть на http://localhost:4000/ у вашому браузері, щоб відкрити Apollo Sandbox — інтерактивний дослідник запитів, де ви можете негайно протестувати ваш API.

5. Визначення вашої схеми

Схема є основою кожного GraphQL API. Інвестування часу в добре розроблену схему приносить дивіденди протягом усього життя вашої програми.

Скалярні типи

GraphQL включає п’ять вбудованих скалярних типів:

    Int — 32-бітне ціле число зі знаком
    Float — число з плаваючою комою подвійної точності
    String — послідовність символів UTF-8
    Boolean — true або false
  • ID — унікальний ідентифікатор, серіалізований як рядок
  • Ви також можете визначити користувацькі скаляри для типів як-от Date, DateTime, Email, URL або JSON.

    Типи об’єктів

    type Author {
      id: ID!
      name: String!
      biography: String
      books: [Book!]!
    }
    
    type Book {
      id: ID!
      title: String!
      author: Author!
      publishedYear: Int
      genre: String
      tags: [String!]
    }

    Модифікатор ! позначає поле, яке не може мати значення null. [Book!]! означає список, який не може мати значення null, з об’єктів Book, які не можуть мати значення null.

    Запити

    type Query {
      books: [Book!]!
      book(id: ID!): Book
      authors: [Author!]!
      author(id: ID!): Author
      booksByGenre(genre: String!): [Book!]!
    }

    Мутації

    type Mutation {
      createBook(title: String!, authorId: ID!, genre: String): Book!
      updateBook(id: ID!, title: String, genre: String): Book
      deleteBook(id: ID!): Boolean!
    }

    Вхідні типи

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

    input CreateBookInput {
      title: String!
      authorId: ID!
      publishedYear: Int
      genre: String
      tags: [String!]
    }
    
    type Mutation {
      createBook(input: CreateBookInput!): Book!
    }

    6. Реалізація Resolvers

    Resolvers — це функції, які виконують кожне поле у вашій схемі. Кожне поле в GraphQL схемі може мати resolver. Якщо для поля не визначено resolver, GraphQL повертається до default resolver, який просто повертає властивість з тим же ім’ям з батьківського об’єкта.

    Сигнатура Resolver

    fieldName: (parent, args, context, info) => value
    • parent — розв’язане значення батьківського типу (корисно для вкладених resolvers).
    • args — аргументи, передані до поля в запиті.
    • context — спільний об’єкт, переданий через весь ланцюг resolver, зазвичай містить автентифікованого користувача, з’єднання з базою даних або data loaders.
    • info — метаінформація про виконання запиту, включаючи ім’я поля та схему.

    Приклад: Resolvers з базою даних

    const resolvers = {
      Query: {
        books: async (_, __, { db }) => {
          return db.collection('books').find().toArray();
        },
        book: async (_, { id }, { db }) => {
          return db.collection('books').findOne({ _id: id });
        },
      },
    
      Mutation: {
        createBook: async (_, { input }, { db, user }) => {
          if (!user) throw new Error('Authentication required');
          const result = await db.collection('books').insertOne(input);
          return { id: result.insertedId, ...input };
        },
      },
    
      Book: {
        // Nested resolver: fetch the author for each book
        author: async (book, _, { db }) => {
          return db.collection('authors').findOne({ _id: book.authorId });
        },
      },
    };

    Уникнення проблеми N+1 за допомогою DataLoader

    Вкладені resolvers можуть спровокувати проблему N+1 запитів — отримання списку з 100 книг, а потім виконання 100 окремих викликів до бази даних для розв’язання автора кожної книги. Рішення — DataLoader, утиліта для групування та кешування:

    import DataLoader from 'dataloader';
    
    // In your context factory:
    const authorLoader = new DataLoader(async (authorIds) => {
      const authors = await db.collection('authors')
        .find({ _id: { $in: authorIds } })
        .toArray();
      return authorIds.map((id) => authors.find((a) => a._id === id));
    });
    
    // In your resolver:
    Book: {
      author: (book, _, { authorLoader }) => authorLoader.load(book.authorId),
    }

    DataLoader групує всі author пошуки в межах одного тику event loop в один запит до бази даних, зменшуючи 100 запитів до 1.

    7. Запити та мутація даних

    Базовий запит

    query GetAllBooks {
      books {
        id
        title
        author {
          name
        }
        genre
      }
    }

    Запит з аргументами

    query GetBook {
      book(id: "1") {
        title
        author {
          name
          biography
        }
        publishedYear
        tags
      }
    }

    Запит зі змінними

    Змінні роблять ваші запити динамічними та запобігають вразливостям впровадження:

    query GetBook($bookId: ID!) {
      book(id: $bookId) {
        title
        author {
          name
        }
      }
    }
    {
      "bookId": "1"
    }

    Приклад мутації

    mutation AddBook($input: CreateBookInput!) {
      createBook(input: $input) {
        id
        title
        author {
          name
        }
      }
    }
    {
      "input": {
        "title": "Designing Data-Intensive Applications",
        "authorId": "42",
        "publishedYear": 2017,
        "genre": "Technology"
      }
    }

    Фрагменти

    Фрагменти дозволяють вам повторно використовувати вибір полів у кількох запитах:

    fragment BookDetails on Book {
      id
      title
      genre
      publishedYear
    }
    
    query {
      books {
        ...BookDetails
        author {
          name
        }
      }
    }

    8. Оновлення в реальному часі з підписками

    GraphQL підписки підтримують постійне з’єднання — зазвичай через WebSockets — і надсилають дані клієнтам, коли на сервері відбуваються певні події.

    Визначення схеми

    type Subscription {
      bookAdded: Book!
      bookUpdated(id: ID!): Book!
    }

    Реалізація сервера (Apollo Server з WebSockets)

    npm install graphql-ws ws @graphql-tools/schema
    import { createServer } from 'http';
    import { WebSocketServer } from 'ws';
    import { useServer } from 'graphql-ws/lib/use/ws';
    import { makeExecutableSchema } from '@graphql-tools/schema';
    import { PubSub } from 'graphql-subscriptions';
    
    const pubsub = new PubSub();
    
    const resolvers = {
      Mutation: {
        createBook: async (_, { input }, { db }) => {
          const book = await db.collection('books').insertOne(input);
          pubsub.publish('BOOK_ADDED', { bookAdded: book });
          return book;
        },
      },
      Subscription: {
        bookAdded: {
          subscribe: () => pubsub.asyncIterator(['BOOK_ADDED']),
        },
      },
    };
    
    const schema = makeExecutableSchema({ typeDefs, resolvers });
    const httpServer = createServer();
    const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql' });
    useServer({ schema }, wsServer);

    Підписка клієнта

    subscription OnBookAdded {
      bookAdded {
        id
        title
        author {
          name
        }
      }
    }

    9. GraphQL Introspection та Developer Tooling

    Система introspection GraphQL є однією з найбільш дружніх до розробників функцій. Запитуючи __schema та __type мета-поля, клієнти та інструменти можуть виявити повну структуру вашого API під час виконання.

    Приклад Introspection Query

    {
      __schema {
        types {
          name
          kind
          description
        }
      }
    }

    Основні Developer Tools

    ІнструментПризначення
    GraphiQLIDE в браузері для написання та тестування запитів
    Apollo StudioПовне управління API, моніторинг продуктивності, реєстр схеми
    PostmanПідтримка GraphQL запитів з управлінням колекціями
    InsomniaЛегкий API клієнт з підтримкою GraphQL
    GraphQL Code GeneratorАвтоматично генерує TypeScript типи з вашої схеми
    Apollo Client DevToolsРозширення браузера для налагодження Apollo Client кешу

    > Примітка безпеки: Вимкніть introspection у виробничих середовищах, щоб уникнути розкриття схеми вашого API потенційним зловмисникам. Apollo Server робить це простим:

    >

    > “`javascript

    > new ApolloServer({ typeDefs, resolvers, introspection: false });

    > “`

    10. Розгортання GraphQL у виробництві

    Переміщення GraphQL API з розробки у виробництво вимагає ретельної уваги до інфраструктури, продуктивності та надійності.

    Вибір правильної інфраструктури хостингу

    Інфраструктура, на якій ви запускаєте свій GraphQL API, безпосередньо впливає на його продуктивність, надійність та масштабованість. Для виробничих навантажень у вас є кілька сильних варіантів:

    VPS Hosting — відмінна відправна точка для більшості GraphQL API. План VPS Hosting надає вам виділені ресурси, root-доступ та свободу налаштування вашого Node.js runtime, зворотного проксі та менеджера процесів саме так, як вам потрібно. VPS плани AlexHost розроблені для навантажень, чутливих до продуктивності, і включають SSD сховище та високопропускну спеціалізовану лінію.

    Dedicated Servers — правильний вибір, коли ваш GraphQL API обробляє великі обсяги запитів, складні робочі навантаження підписок або служить шлюзом, що агрегує кілька мікросервісів. З Dedicated Server ви отримуєте виключний доступ до всіх ресурсів CPU, RAM та I/O — без шумних сусідів, без конкуренції за ресурси та з необхідною потужністю для обробки тисяч одночасних WebSocket з’єднань для підписок.

    GPU Hosting варто розглянути, якщо ваш GraphQL API служить рівнем інтерфейсу для машинного навчання, конвеєрів обробки даних у реальному часі або функцій на основі AI. GPU Hosting від AlexHost надає вам доступ до ресурсів NVIDIA GPU, дозволяючи вашому API надавати обчислювально інтенсивні результати з низькою затримкою.

    Стек виробничого розгортання

    Надійне виробниче розгортання для GraphQL API зазвичай виглядає так:

    Client → CDN / Load Balancer → Nginx (Reverse Proxy) → Node.js (PM2) → Database
                                                          ↘ Redis (Caching / PubSub)

    Крок 1: Встановіть та налаштуйте Nginx як зворотний проксі

    server {
        listen 80;
        server_name api.yourdomain.com;
    
        location /graphql {
            proxy_pass http://localhost:4000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_cache_bypass $http_upgrade;
        }
    }

    Заголовки Upgrade та Connection критичні для підтримки WebSocket, що забезпечує GraphQL підписки.

    Крок 2: Керуйте вашим Node.js процесом за допомогою PM2

    npm install -g pm2
    pm2 start index.js --name graphql-api --instances max
    pm2 save
    pm2 startup

    --instances max дозволяє режим кластера, запускаючи один робочий процес на ядро CPU для максимізації пропускної здатності.

    Крок 3: Захистіть за допомогою SSL

    Кожен виробничий API повинен обслуговуватися через HTTPS. SSL Certificate від AlexHost забезпечує шифрування всіх даних під час передачі між клієнтами та вашою GraphQL точкою доступу. Це особливо важливо для API, які обробляють токени аутентифікації, персональні дані або фінансову інформацію.

    # Install Certbot and obtain a certificate
    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d api.yourdomain.com

    Крок 4: Зареєструйте свій домен

    Вашому API потрібен запам’ятовуваний, професійний домен. Domain Registration через AlexHost надає вам доступ до всіх основних TLD з простим керуванням DNS, що полегшує вказування вашого домену на ваш сервер та налаштування піддоменів для проміжних та виробничих середовищ.

    Стратегії кешування

    Модель одноточкового доступу GraphQL означає, що кешування на рівні HTTP (яке залежить від диференціації URL) не працює з коробки. Замість цього використовуйте ці стратегії:

    • Persisted Queries — клієнти надсилають хеш запиту замість повного рядка запиту, дозволяючи кешування CDN за хешем.
    • Response Caching — кешуйте результати резолвера в Redis на основі хеша запиту та змінних.
    • DataLoader — групуйте та кешуйте виклики бази даних під час виконання одного запиту.
    • Apollo Cache — нормалізований кеш на стороні клієнта, який усуває надлишкові мережеві запити.

    11. Найкращі практики безпеки

    Гнучкість GraphQL — це палиця з двома кінцями. Без належних захисних заходів один шкідливий запит може вичерпати ресурси вашого сервера.

    Обмеження глибини запиту

    Запобігайте глибоко вкладеним запитам, які викликають рекурсивні пошуки в базі даних:

    import depthLimit from 'graphql-depth-limit';
    
    new ApolloServer({
      typeDefs,
      resolvers,
      validationRules: [depthLimit(7)],
    });

    Аналіз складності запиту

    Призначте вартість кожному полю та відхиліть запити, які перевищують бюджет складності:

    import { createComplexityLimitRule } from 'graphql-validation-complexity';
    
    new ApolloServer({
      validationRules: [createComplexityLimitRule(1000)],
    });

    Обмеження частоти запитів

    Застосуйте обмеження частоти запитів на рівні Nginx або у вашому додатку, використовуючи бібліотеку на кшталт express-rate-limit для запобігання зловживанню.

    Аутентифікація та авторизація

    Використовуйте функцію context для приєднання автентифікованого користувача до кожного запиту:

    const server = new ApolloServer({
      typeDefs,
      resolvers,
      context: async ({ req }) => {
        const token = req.headers.authorization?.split('Bearer ')[1];
        const user = token ? await verifyToken(token) : null;
        return { user, db, authorLoader };
      },
    });

    Потім забезпечте авторизацію в резолверах:

    createBook: (_, { input }, { user }) => {
      if (!user || !user.roles.includes('EDITOR')) {
        throw new ForbiddenError('You do not have permission to create books.');
      }
      // proceed with creation
    },

    Вимкніть внутрішній огляд у виробництві

    new ApolloServer({
      introspection: process.env.NODE_ENV !== 'production',
    });

    Валідація вхідних даних

    Ніколи не довіряйте вхідним даним від клієнта. Валідуйте всі аргументи мутацій, використовуючи бібліотеку на кшталт joi або zod, перш ніж передавати дані до вашого шару бази даних.

    12. Висновок

    GraphQL представляє значний крок вперед у філософії дизайну API. Надаючи клієнту контроль над отриманням даних, забезпечуючи строго типізовану схему як контракт між системами та надаючи вбудовану підтримку підписок у реальному часі, GraphQL дозволяє командам розробників будувати швидше, випускати з більшою впевненістю та ітерувати без тертя версіонування API.

    Ключові концепції, які слід запам’ятати з цього посібника:

    • Дизайн, орієнтований на схему, створює більш підтримуваних, самодокументованих API.
    • Резолвери — це міст між вашою схемою та вашими джерелами даних — тримайте їх легкими та делегуйте важку роботу сервісним або рівням доступу до даних.
    • DataLoader необхідний для виробничих GraphQL API — ніколи не дозволяйте вкладеним резолверам генерувати необмежені запити до бази даних.
    • Підписки розблоковують можливості реального часу без додавання окремої інфраструктури WebSocket.
    • Безпека вимагає навмисної уваги — обмеження глибини, аналіз складності, аутентифікація та вимкнення інтроспекції у виробництві є обов’язковими для публічних API.
    • Інфраструктура має значення — добре написаний GraphQL API заслуговує на хостинг, який може йому відповідати.

    Незалежно від того, чи ви починаєте з плану VPS Hosting для нового проекту, масштабуєтесь до Dedicated Server у міру зростання вашої користувацької бази, чи використовуєте GPU Hosting для функцій API на основі AI, AlexHost надає інфраструктурну основу, яка потрібна вашому GraphQL API для надійної роботи на кожному етапі зростання.

    Почніть будувати. Ваші клієнти чекають, щоб попросити саме ті дані, які їм потрібні.