Записки программиста #2, GraphQL
В этой записке расскажу немного о GraphQL и с тем как я его на Spring накручивал и небольшой опыт о попытке реализовать ApiGateway.
Для тех кто не вкурсе, расскажу немного. GraphQL это альтернатива RestFul, отличие в том, что в GraphQL есть только один endpoint, который принимает запросы на специальном языке, разбирает запрос на АСТ токены и вызывает различные резолверы на сервере для загрузки данных. В отличии от REST, GraphQL позволяет выбирать самостоятельно данные которые клиентское приложение захочет получить. Например у нас есть такая модель
{
"id": 1,
"title": "Записки программиста #2, GraphQL",
"rating": 4.4
"author": {
"id": 2,
"name": "Вячеслав Гуссер"
}
}
Это представление поста которое отдается по rest api, если мы сделаем запрос на API, то мы получим такую модель, можно извратиться и сделать API гибким на получение различных моделей, но это не очень. Альтернатива - GraphQL, допустим мне надо получить только название статьи, без рейтинга и от автора только имя, тогда мы напишем такой GraphQL запрос:
query {
post(id: 1) {
title
author {
name
}
}
}
Этот запрос выполнит метод post(long id), на бекенде и из вернувшейся модели сформирует нам ответ с данными которые мы захотели на клиенте (это так если не вдаваться в подробности). Красивый подход, вроде даже удобно, нет ругани с фронтенд разработчками по моделями. И так как этот QL можно использовать по http, то мы получаем масштабируемое решение. Но есть одно НО, нам надо описывать схемы и типы данных, а это приводит к проблемам в распределенной системе.
Про установку на spring.
Я столкнулся с рядом проблем.
- При установке ранних версий, например 4.3 - 4.4, мы получаем GraphQLServlet который работает через MultipartData, на который клиент не может послать нормально запрос, соответственно еще и интерфейс GraphiQL для выполнения запросов тестирования тоже не работает
- Не понятные сообщения об ошибках, которые я смог понять только продебажив код.
- Не приятные ограничения GraphQL, у вас не может быть бекенда на котором нет хотя бы одного запроса, у вас не может быть бекенда который состоит только из операций мутации
Первая проблема решается просто выбором версии, если Вы используете Spring Boot 2.0.+, то просто ставьте последнюю версию стартера и все будет ок.
Вторая проблема вытекла у меня из третьей, я написал такую схему:
schema {
query: Query
mutation: Mutation
}
type Query {
}
type Mutation {
createCallback(request: Callback): Status
}
input Callback {
//
}
type Status {
//
}
И я получал NullPointerException с непонятной ошибкой, вот как Вы думаете? Может ли быть бекенд без запросов на чтение? Отвечу за Вас, конечно может! Но GraphQL так не думает, ошибка была в том, что тип Query у меня был пустым и мне пришлось писать что-то такое
schema {
query: Query
mutation: Mutation
}
type Query {
_: Boolean
}
type Mutation {
createCallback(request: Callback): Status
}
input Callback {
//
}
type Status {
//
}
Тогда у меня все завелось. Потом я уже увидел на github и еще позже в спеке, что пустых типов в GraphQL быть не может и то что Query обязательный. P.S решение третьей проблемы так же выше.
Проблема N+1, для коллекций с сущностями и связями там побороли с помощью @Batch резолверов, об этом можно не переживать.
Ну и последнее о чем я хотел бы сказать. Это динамический ApiGateway в микросервисной архитектуре для пачки микросервисов. Мне хотелось написать следующий Gateway для своих сервисов:
- Чтобы я мог легко добавлять новые микросервисы и их эндпоинты в gateway
- Чтобы я мог применять различные фильтры (например авторизацию) для определенных сервисов или эндпоинтов
- Чтобы я мог писать код который сможет изменять ответы от сервисов так как мне нужно.
GraphQL классно решает последнюю проблему, и я хотел сделать это именно на graphql. Но как только я попытался, то встала проблема. Если я буду использовать GraphQL, то он будет сильно конфликтовать с первым требованием.
Я не смогу легко добавлять новые сервисы и эндпоинты и вот почему.
- Мне надо расширить схему
- Мне надо добавить новые типы
- Мне надо добавить реализацию этих типо в Java коде
Это не то что я хотел. По-этому я сделал иначе.
Решить эту проблему можно, но у меня не было достаточно времени на правильное решение данной проблемы.
В итоге:
GraphQL - классная технология, ее можно использовать в новых сервисах, но интегрировать ее как ApiGateway не так просто, если Вам конечно не все равно на свое время