Добавим еще одну технологию в наше резюме, разобравшись с GraphQL.

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

Однако при использовании REST API возникает несколько распространенных проблем:

  • Избыточность данных (Over-fetching): API возвращает больше данных, чем необходимо. Клиенту может быть нужно всего одно значение.
  • Недостаточность данных (Under-fetching): иногда мы не получаем все необходимые данные за один запрос. Требуется выполнить несколько вызовов, чтобы получить связанную информацию.
  • Множественные запросы к API: особенно от этого страдают мобильные приложения, которым приходится отправлять большое количество запросов.

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

Что такое GraphQL?

  • GraphQL — это язык запросов для API, который позволяет пользователю запрашивать только те данные, которые ему необходимы.
  • Он был разработан компанией Meta Platforms (Facebook) и выпущен в 2015 году.
  • Вместо множества эндпоинтов (адресов), как в традиционных API, GraphQL использует один эндпоинт, где клиент сам указывает, какие данные он хочет получить.

Пример

Предположим, у нас есть API для работы с пользователями (User API). В REST мы можем получить следующее:

{
"id":1,
"name":"Alexa",
"email":"alexa@gmail.com",
"address":"India",
"phone":"123456789"
}

Но если клиенту нужно только имя, GraphQL позволяет запросить лишь его.

--GraphQL Query--

jquery {
user(id:1) {
name
}
}
/*Ответ */
{
"data": {
"user": {
"name": "Alexa"
}
}
}

Архитектура GraphQL

Система GraphQL в основном состоит из трех важных частей:

  1. Схема (Schema)
  2. Резолвер (Resolver)
  3. GraphQL-сервер (GraphQL Server)

Схема (Schema) определяет, какие данные доступны в API.

// Пример

type User {
id: ID
name: String
email: String
}

Резолвер (Resolver) — это функция, которая извлекает данные. Резолверы связывают GraphQL-запросы с базой данных или другими сервисами.

// Пример

public User getUserById(Long id){
return userRepository.findById(id);
}

GraphQL-сервер — Сервер обрабатывает:

  • запрос клиента;
  • валидацию схемы;
  • выполнение резолверов;
  • формирование ответа.

GraphQL в основном поддерживает три типа операций:

  1. Запросы (Queries) — используются для получения данных.
  2. Мутации (Mutations) —используются для создания, обновления или удаления данных.
  3. Подписки (Subscriptions) — используются для обновлений в реальном времени. Подписки часто работают через веб-сокеты.

Создадим пример проекта, используя все три операции. Для разработки GraphQL-проекта вам понадобятся 2 зависимости.

<!-- Source: https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<!-- Source: https://mvnrepository.com/artifact/com.graphql-java-kickstart/graphql-spring-boot-starter -->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
</dependency>

В resources (ресурсы) необходимо указать имя файла — schema.graphqls.

src/main/resources/graphql/schema.graphqls

Именно в этом файле graphqls мы и пишем наши запросы.

Эта схема определяет:

  • запрос — для получения данных →  messages;
  • мутацию — для создания, обновления или удаленияsendMessage.
  • подписку — messageAdded.
type Message {
    id: ID
    content: String
    sender: String
}

type Query {
    messages: [Message]
}

type Mutation {
    sendMessage(content: String, sender: String): Message
}

type Subscription {
    messageAdded: Message
}

Message.java — класс-модель для определения атрибутов:

@Data
public class Message {

private String id;
private String content;
private String sender;

public Message(){}

public Message(String id, String content, String sender){
this.id=id;
this.content=content;
this.sender=sender;
}
}

Сервис сообщений (Message Service)

Обрабатывает хранение данных и события подписок.

@Service
public class MessageService {

private List<Message> messages = new ArrayList<>();

private Sinks.Many<Message> sink =
Sinks.many().multicast().onBackpressureBuffer();

public List<Message> getMessages(){
return messages;
}

public Message sendMessage(String content, String sender){

Message message = new Message(
UUID.randomUUID().toString(),
content,
sender
);

messages.add(message);

sink.tryEmitNext(message);

return message;
}

public Flux<Message> messageStream(){
return sink.asFlux();
}
}

Контроллер:

@Controller
public class MessageController {

private final MessageService messageService;

public MessageController(MessageService messageService){
this.messageService = messageService;
}

@QueryMapping
public List<Message> messages(){
return messageService.getMessages();
}

@MutationMapping
public Message sendMessage(
@Argument String content,
@Argument String sender){

return messageService.sendMessage(content, sender);
}

@SubscriptionMapping
public Flux<Message> messageAdded(){
return messageService.messageStream();
}
}

Теперь запустим приложение для теста:

# используем запрос для получения данных 
query {
messages {
id
content
sender
}
}

# Ответ

{
"data": {
"messages": [
{
"id":"1",
"content":"Hello",
"sender":"Anusha"
}
]
}
}

Пример мутации:

mutation {
sendMessage(content:"Hello GraphQL", sender:"Alexa"){
id
content
sender
}
}

Пример подписки:

subscription {
messageAdded {
id
content
sender
}
}

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

Как работает этот пример проекта:

  1. Клиент отправляет запрос (query) → GraphQL-сервер проверяет схему → GraphQL вызывает функции-резолверы → Резолвер получает данные из базы данных → GraphQL формирует ответ.
  2. Клиент отправляет мутацию для создания сообщения.
  3. Сообщение сохраняется в сервисе.
  4. Событие отправляется через Flux-поток.
  5. Все клиенты, подписанные на messageAdded, получают обновление.

GraphQL в основном используется в следующих случаях:

  • Мобильные приложения, которым нужны индивидуальные наборы данных.
  • Системы, где существует множество микросервисов.
  • Проекты с часто меняющимся фронтендом.
  • Приложения, где необходимо сократить количество вызовов API

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Anusha SP: Exploring GraphQL: An Easy Addition to Your Backend Tech Stack

Предыдущая статьяОбеспечение доступности во Frontend-разработке: стандарты и практики 2026 года