(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Наверное вы слышали про такой стандарт API как GraphQL. Если посмотреть на главную страницу их сайта https://graphql.org/, то там бросается в глаза фраза: "Evolve your API without versions".
Если воспринимать ее буквально, то можно подумать: "О, круто, API без версионирования! А что так можно было?)"

Но как это обычно бывает в разработке - не все так просто.

Если подумать - API без версионирования и без сопутствующих ему проблем, в частности несовместимых изменений, может быть только в том случае, если в API вообще нет обязательных полей. Но полезность такого API стремится к нулю. А точнее это уже не API, а что-то похоже на поиск Google или Yandex или общение с ChatGPT.
В GraphQL конечно же обязательные поля есть. Единственный момент - по умолчанию все поля не обязательны.

А если подумать еще - есть еще один способ. Завязаться на какой-то стандарт уровня HTTP, HTML или SWIFT, у которого так много потребителей, что волей неволей придется поддерживать обратную совместимость. Матерится сквозь зубы, но поддерживать) И то, даже в таких областях появляются новые версии API.
Плюс можно добавить уровень API шлюза - наружу выдаем API по стандарт, внутри - свое, которое может меняться свободно.
Но напрямую к GraphQL этот кейс не относится, это можно сделать и с REST, и с JSON-RPC.

Но если вчитаться в документацию GraphQL внимательнее, то видно, что авторы предлагают другое - эволюцию API мелкими шагами без явного задания версий.
https://principledgraphql.com/agility/#5-use-an-agile-approach-to-schema-development
Agile в деле построения API.
По сути это старый добрый принцип:
1) добавляем новый метод в API
2) старый объявляем deprecated
3) уведомляем об этом потребителей, не забывая про дату вывода из эксплуатации
4) когда придет время удаляем старое API
Profit!

В GraphQL выглядит это вот так:

type Account {
surname: String! @deprecated(reason: "Use personSurname")
personSurname: String
}

В чем тут могут быть проблемы:
1) не факт, что потребители вовремя обновятся. Да, deprecated на уровне API лучше, чем рассылка потребителям или страничка в сети, но это не панацея. К слову, OpenAPI тоже так умеет.
2) да, контролировать потребителей на уровне отдельного deprecated поля в GraphQL гораздо проще: возможность на клиенте указывать только нужные поля - это наверное главная фишка GraphQL. Но не все потребители будут так делать. Некоторые - сознательно, нарушая конвенцию использования GraphQL, некоторые - случайно, просто забыв убрать лишние поля
3) если работать до последнего потребителя - API быстро превратится в помойку
4) а главное: если заводить множество мелких изменений в API - каждый спринт по изменению - со временем очень сложно станет этим управлять. Да, есть инструменты, облегчающие управление - https://github.com/kamilkisiela/graphql-inspector Да, нужна четкая политика по работе с изменениями API. Но у меня есть сомнения, будет ли это все работать при непрерывном потоке изменений в большой организации без введения новых версий. Как и Agile в целом такой подход требует ответственности от команды и также плохо масштабируется.

Ну и последнее. Да, ничего для создания версий в GraphQL нет. Но никто не мешает развернуть рядом endpoint и назвать его graphql/v2. Или в схему к полю xyz добавить поле xyzV2 )))

#api #graphql #versioning
Всем привет!

Самая крутая фича GraphQL - это возможность явного указания какие данные нужны клиенту.
Причем фильтровать можно на любом уровне вложенности объектов.
И к тому же фильтровать не только по возвращаемым полям, но и по списку записей - аналог WHERE в SQL.
Пример запроса:

{
authors(surname: "Пушкин") {
name,
surname,
books(year: "1831")) {
title,
genre,
year
}
}
}

На стороне сервера для каждого объекта в запросе - в моем примере Author и Book - можно написать свой fetcher, независимо вытаскивающий данные из хранилища.
А вишенка на торте - с помощью Federation https://netflix.github.io/dgs/advanced/federated-testing/ можно децентрализовать схему, расположив fetchers в разных микросервисах.

Но главный плюс также является и главной потенциальной проблемой.
GraphQL подталкивает к тому, чтобы был один endpoint, через который можно получить все данные.
А если потребители захотят получить все?)

Встают вопросы:
1) разграничения доступа. В целом решается интеграцией со Spring Security https://netflix.github.io/dgs/advanced/security/ Можно расставить аннотации @Secured над каждым объектом. Но я вижу больше рисков по сравнению с специальным REST endpoint, "заточенным" под определенный набор данных.
2) производительности - ведь одним запросом к GraphQL сервису в теории можно вытащить все содержимое БД. А скорее получить проблему N+1 и подвесить БД). Авторы естественно знают об этой проблеме https://netflix.github.io/dgs/data-loaders/ и предлагают решение: batching и кэширование. Но решение не коробочное, требуется проектирование

P.S. Еще одна крутая фича - graphiql - интерактивная веб-консоль для построения запросов, включенная по умолчанию https://github.com/graphql/graphiql C auto-completion.
Ну и конечно возможность подписки на события как часть протокола GraphQL. Реализуется как правило через WebsSocket https://netflix.github.io/dgs/advanced/subscriptions/

#graphql #api