Введение в GraphQL API на Java
GraphQL — это язык запросов для API, который предоставляет клиентам возможность запрашивать только те данные, которые им действительно нужны. В отличие от REST, где структура ответа фиксирована, GraphQL позволяет гибко формировать ответы, что существенно снижает объем передаваемых данных и ускоряет разработку.
В этом туториале мы на практике разберем, как создать GraphQL API с Java с использованием библиотеки graphql-java и фреймворка Spring Boot. Вы узнаете, как настроить схему, написать резолверы и выполнять запросы.
Статья будет полезна Java-разработчикам, которые хотят освоить современный подход к построению API и улучшить взаимодействие между клиентом и сервером.
1. Настройка проекта и зависимости
Для начала создадим новый проект Spring Boot. Удобнее всего использовать Spring Initializr. Добавим следующие зависимости:
- Spring Web — для запуска веб-сервера
- Spring Boot DevTools — для ускорения разработки
- Lombok — для сокращения шаблонного кода
После создания проекта добавьте в pom.xml основную библиотеку GraphQL:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-spring-boot-starter-webmvc</artifactId>
<version>2021-06-30T00-00-00-1e4b5e5</version>
</dependency>
Также понадобится библиотека для работы с инструментом GraphiQL (веб-интерфейс для тестирования запросов):
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>5.0.2</version>
</dependency>
После добавления зависимостей обновите проект и запустите его. По умолчанию GraphiQL будет доступен по адресу http://localhost:8080/graphiql.
2. Создание модели данных и схемы GraphQL
Для демонстрации создадим простую модель Book (книга). Определим класс с полями id, title, author и pages.
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 int pages;
}
Теперь необходимо определить схему GraphQL. Создайте файл schema.graphqls в папке src/main/resources:
type Query {
allBooks: [Book]
bookById(id: String): Book
}
type Book {
id: String
title: String
author: String
pages: Int
}
Схема описывает два запроса: получение всех книг и получение книги по идентификатору. Тип Book содержит четыре поля.
Для обработки запросов создадим сервис, который будет хранить данные в памяти (для простоты):
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class BookService {
private List<Book> books = new ArrayList<>();
@PostConstruct
public void init() {
books.add(new Book("1", "Война и мир", "Лев Толстой", 1225));
books.add(new Book("2", "Преступление и наказание", "Фёдор Достоевский", 671));
books.add(new Book("3", "Мастер и Маргарита", "Михаил Булгаков", 480));
}
public List<Book> getAllBooks() {
return books;
}
public Book getBookById(String id) {
Optional<Book> book = books.stream()
.filter(b -> b.getId().equals(id))
.findFirst();
return book.orElse(null);
}
}
3. Реализация резолверов (GraphQL Resolvers)
Резолверы — это классы, которые связывают запросы из схемы с реальными данными. В библиотеке graphql-java-spring-boot-starter-webmvc используется аннотация @QueryMapping.
Создадим класс BookResolver:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
@Controller
public class BookResolver {
@Autowired
private BookService bookService;
@QueryMapping
public List<Book> allBooks() {
return bookService.getAllBooks();
}
@QueryMapping
public Book bookById(@Argument String id) {
return bookService.getBookById(id);
}
}
Обратите внимание на аннотацию @Argument — она позволяет передавать параметры из запроса GraphQL в метод.
Теперь, если запустить приложение и открыть GraphiQL, можно выполнить следующий запрос:
query {
allBooks {
id
title
author
}
}
Ответ вернет только запрошенные поля. Например:
{
"data": {
"allBooks": [
{ "id": "1", "title": "Война и мир", "author": "Лев Толстой" },
{ "id": "2", "title": "Преступление и наказание", "author": "Фёдор Достоевский" },
{ "id": "3", "title": "Мастер и Маргарита", "author": "Михаил Булгаков" }
]
}
}
Если нужно получить конкретную книгу, используйте запрос с аргументом:
query {
bookById(id: "2") {
title
pages
}
}
4. Добавление мутаций (Mutation) для изменения данных
GraphQL поддерживает не только чтение, но и изменение данных через мутации. Добавим возможность добавлять новую книгу.
Сначала расширим схему в файле schema.graphqls:
type Mutation {
addBook(title: String!, author: String!, pages: Int!): Book
}
Затем добавим метод в сервис BookService:
public Book addBook(String title, String author, int pages) {
String newId = String.valueOf(books.size() + 1);
Book book