Введение в GraphQL и Java
GraphQL — это современный язык запросов для API, разработанный Facebook. В отличие от REST, где каждый эндпоинт возвращает фиксированную структуру данных, GraphQL позволяет клиенту запрашивать именно те поля, которые ему нужны. Это снижает объем передаваемых данных и упрощает разработку сложных интерфейсов.
В этом туториале мы создадим простой GraphQL API на Java с использованием Spring Boot и библиотеки graphql-java. Вы узнаете, как настроить проект, определить схему, реализовать резолверы и протестировать API. Статья ориентирована на начинающих, поэтому мы будем двигаться шаг за шагом.
Для работы вам понадобятся: JDK 11+, Maven или Gradle, IDE (IntelliJ IDEA, Eclipse) и базовые знания Java.
1. Настройка проекта Spring Boot
Начнем с создания нового проекта Spring Boot. Самый простой способ — использовать Spring Initializr. Выберите следующие зависимости:
- Spring Web
- Spring Boot DevTools
- Lombok (опционально, для упрощения кода)
После генерации проекта добавьте в pom.xml (или build.gradle) зависимость для GraphQL:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>5.2.4</version>
</dependency>
Эти библиотеки упростят интеграцию GraphQL с Spring Boot. После обновления зависимостей запустите проект командой mvn spring-boot:run или через IDE.
2. Определение схемы GraphQL
Схема — это основа GraphQL API. Она описывает типы данных, запросы (queries) и мутации (mutations). Создайте файл schema.graphqls в папке src/main/resources:
type Book {
id: ID!
title: String!
author: String!
year: Int
}
type Query {
books: [Book]
bookById(id: ID!): Book
}
type Mutation {
addBook(title: String!, author: String!, year: Int): Book
}
Здесь мы определили тип Book с обязательными полями id, title, author и необязательным year. Query содержит два запроса: получение всех книг и книги по ID. Mutation позволяет добавлять новые книги.
Обратите внимание на восклицательный знак — он обозначает обязательное поле (non-null).
3. Реализация резолверов
Резолверы (resolvers) — это Java-классы, которые связывают схему с данными. Создадим класс Book как модель данных:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private String id;
private String title;
private String author;
private Integer year;
}
Теперь создадим сервис для хранения книг (в реальном проекте здесь будет подключение к БД):
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Service
public class BookService {
private List<Book> books = new ArrayList<>();
@PostConstruct
public void init() {
books.add(new Book("1", "Война и мир", "Лев Толстой", 1869));
books.add(new Book("2", "Преступление и наказание", "Фёдор Достоевский", 1866));
}
public List<Book> getAllBooks() {
return books;
}
public Optional<Book> getBookById(String id) {
return books.stream().filter(b -> b.getId().equals(id)).findFirst();
}
public Book addBook(String title, String author, Integer year) {
String id = UUID.randomUUID().toString();
Book book = new Book(id, title, author, year);
books.add(book);
return book;
}
}
И, наконец, резолверы для запросов и мутаций:
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class QueryResolver implements GraphQLQueryResolver {
@Autowired
private BookService bookService;
public List<Book> getBooks() {
return bookService.getAllBooks();
}
public Book getBookById(String id) {
return bookService.getBookById(id).orElse(null);
}
}
import com.coxautodev.graphql.tools.GraphQLMutationResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MutationResolver implements GraphQLMutationResolver {
@Autowired
private BookService bookService;
public Book addBook(String title, String author, Integer year) {
return bookService.addBook(title, author, year);
}
}
Обратите внимание: имена методов в резолверах должны совпадать с именами полей в схеме (например, getBooks соответствует books).
4. Тестирование API с помощью GraphiQL
GraphiQL — это встроенная IDE для тестирования GraphQL запросов. Добавьте зависимость в pom.xml:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>5.0.2</version>
</dependency>
Теперь запустите приложение и откройте браузер по адресу http://localhost:8080/graphiql. Вы увидите интерфейс для отправки запросов. Попробуйте выполнить:
query {
books {
id
title
author
year
}
}
Ответ должен содержать список книг. Теперь протестируем мутацию:
mutation {
addBook(title: "Мастер и Маргарита", author: "Михаил Булгаков", year: 1967) {
id
title
author
}
}
После выполнения мутации вы увидите новую книгу в ответе. Можно также запросить книгу по ID:
query {
bookById(id: "1") {
title
author
}
}
GraphQL позволяет комбинировать запросы