Уявіть собі великий офіс, в якому є десятки відділів. Кожен відділ відповідає тільки за свою частину роботи, а клієнти повинні бігати між відділами, щоб зібрати всю потрібну інформацію. Цей офіс — ваш мікросервісний проєкт, а клієнти — це фронтенд-додаток. Біганина між відділами — це ваші HTTP-запити до REST API. Жахливо, правда? Тут на допомогу приходить GraphQL, який виступає як єдина інформаційна стійка, де можна запросити все через одне вікно.
Єдина точка входу
GraphQL дозволяє створити єдиний фасад для всіх мікросервісів. Весь трафік іде через GraphQL-сервер, який агрегує дані з кожного сервісу. Наприклад:
- Сервіс користувачів (User Service) зберігає інформацію про користувачів.
- Сервіс замовлень (Order Service) відповідає за замовлення користувачів.
- Сервіс відгуків (Review Service) керує відгуками на продукти.
Замість того щоб клієнт робив запити до трьох окремих точок REST API, він робить один запит до GraphQL. GraphQL-сервер сам розбереться, куди звертатися.
Приклад архітектури з GraphQL
+---------------+ +---------------------+
| CLIENT | --> | GraphQL API |
+---------------+ +---------+-----------+
|
+------------------------+------------------------+
| | |
+---------------+ +---------------------+ +-----------------+
| User Service | | Order Service | | Review Service |
+---------------+ +---------------------+ +-----------------+
Чому це зручно? Бо клієнту не треба турбуватися про те, де й як зберігаються дані. Йому достатньо знати, що GraphQL API надасть всю потрібну інформацію.
Агрегація даних з кількох мікросервісів
Проблема REST
Припустимо, треба вивести на сторінці профілю користувача:
- Ім'я користувача.
- Список його замовлень.
- Відгуки про ці замовлення.
З REST все виглядає так:
- Відправляється запит у User Service для отримання імені користувача.
- На основі ID користувача відправляється другий запит в Order Service для отримання замовлень.
- Для кожного замовлення відправляються запити в Review Service, щоб отримати відгуки.
Це десятки запитів, які займають багато часу і перевантажують мережу. Це як ходити в три магазини, щоб зібрати одну вечерю.
Як GraphQL вирішує цю проблему
GraphQL дозволяє об'єднати всю цю інформацію в одному запиті. Ви створюєте схему, яка описує всі залежності між даними, а сервер GraphQL виконує складну логіку за вас. Ось приклад:
query GetUserProfile($userId: ID!) {
user(id: $userId) {
name
orders {
id
items
reviews {
rating
comment
}
}
}
}
У відповіді ви отримаєте єдиний JSON, що містить потрібні дані:
{
"data": {
"user": {
"name": "Іван Іванов",
"orders": [
{
"id": "123",
"items": ["item1", "item2"],
"reviews": [
{
"rating": 5,
"comment": "Чудово!"
}
]
}
]
}
}
}
При цьому клієнту зовсім не важливо, з яких джерел ці дані прийшли — GraphQL Server уже все зробив за нього.
Покращення клієнтської взаємодії
Проблема Over-fetching і Under-fetching
У REST API ви або отримуєте забагато даних (over-fetching), або замало (under-fetching). Наприклад:
- Ви запитуєте список користувачів, але REST повертає не тільки імена, а й адреси, дати народження та інші непотрібні дані.
- Ви запитуєте конкретного користувача, але REST API не надає поле
orders, і вам доводиться робити додатковий запит.
GraphQL дозволяє клієнтам запитувати рівно те, що потрібно. Якщо користувачу потрібен тільки список імен, він може запросити тільки поле name:
query {
users {
name
}
}
Відповідь буде простою й акуратною:
{
"data": {
"users": [
{ "name": "Іван" },
{ "name": "Марія" },
{ "name": "Петро" }
]
}
}
Переваги для фронтенду
- Менше запитів, менше гальм
Тепер клієнт виконує всього один запит, а не три-чотири, економлячи мережеві ресурси. - Гнучкість UI
Якщо дизайн сторінки змінюється і потрібно додати або прибрати дані, це можна вирішити зміною GraphQL-запиту без модифікації серверного коду. - Реактивність
За допомогою підписок (Subscriptions) GraphQL дозволяє клієнтам отримувати оновлення в реальному часі. Це особливо корисно для повідомлень, систем чатів і динамічних інтерфейсів.
Практика: налаштування мікросервісів з GraphQL
Крок 1. Створюємо схему
Створіть файл schema.graphqls у вашому GraphQL-сервері. Наприклад:
type User {
id: ID
name: String
orders: [Order]
}
type Order {
id: ID
items: [String]
reviews: [Review]
}
type Review {
rating: Int
comment: String
}
type Query {
user(id: ID!): User
}
Крок 2. Налаштовуємо резолвери
У GraphQL-сервері (на Spring Boot) налаштуйте резолвери. Наприклад:
@Component
public class UserResolver implements GraphQLQueryResolver {
private final UserService userService;
public UserResolver(UserService userService) {
this.userService = userService;
}
public User getUser(Long id) {
return userService.getUserById(id);
}
}
Тепер щоразу, коли ви запитуєте поле user, викликається метод getUser.
Крок 3. Агрегація даних
Якщо дані для полів orders і reviews знаходяться в різних мікросервісах, налаштуйте Data Fetchers:
@Component
public class OrderDataFetcher implements DataFetcher<List<Order>> {
private final OrderService orderService;
public OrderDataFetcher(OrderService orderService) {
this.orderService = orderService;
}
@Override
public List<Order> get(DataFetchingEnvironment env) {
User user = env.getSource();
return orderService.getOrdersForUser(user.getId());
}
}
Крок 4. Тестування
Використовуйте GraphQL Playground для відправки запитів і перевірки відповідей. Наприклад:
query {
user(id: 1) {
name
orders {
id
items
reviews {
rating
comment
}
}
}
}
Тепер у вас є уявлення, як GraphQL стає "все-в-одному" фасадом для мікросервісної системи. Він спрощує взаємодію, робить API доступним і зручним, а клієнтам дає гнучкість у запитах.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ