Всем привет!
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые типы потребителей. О версионировании нужно подумать заранее.
2) Сервер и клиенты поддерживают работу с несколькими версиями API. Это позволит избежать синхронных внедрений двух и более микросервисов. Синхронное внедрение - это сложно и повышает вероятность нарушить все наши "девятки" (SLA)
3) API описано схемой. Король горы для REST запросов - OpenAPI. Отмечу, что в отличие от JSON Schema или XSD OpenAPI описывает не модель данных, а web сервис целиком: поддерживаемые HTTP методы - GET, POST,..., коды ответов HTTP, параметры запроса, заголовки.
4) CDC тестирование - https://martinfowler.com/articles/consumerDrivenContracts.html#Consumer-drivenContracts
В чем суть: создается контракт - человеко и машиночитаемое описание тест-кейсов для API, на основании которых генерируются API тесты для поставщика и потребителя. Примеры реализаций:
Spring Cloud Contract https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/getting-started.html#getting-started-three-second-tour
Pact https://docs.pact.io/5-minute-getting-started-guide
Надо отметить, что OpenAPI и CDS в ряде моментов дублируют информацию, об этой проблеме и возможном решении для Spring можно почитать тут: https://springframework.guru/defining-spring-cloud-contracts-in-open-api/
5) API должно предусматривать уникальный идентификатор запроса, обеспечивающий идемпотентность - возможность повторного вызова метода API, не приводящего к дублированию данных на сервере. В сети и на сервере случаются сбои, повтор вызова в этом случае - естественный выход из ситуации. При получении второго и последующего запросов сервер, определив по уникальному идентификатору, что он уже получал этот запрос, должен вернуть текущий статус операции
6) API должно содержать trace_id - уникальный идентификатор операции. trace_id генерируется на клиенте и копируется в каждый последующий запрос по всем микросервисам. Потом с помощью таких инструментов, как Jaeger дерево запросов визуализируется, что упрощает отлавливание ошибок
7) в API не должно быть ничего лишнего. Добавляем то, что нужно клиенту, если появляется новые требования - версионируем API. Иначе получим аналог "божественного объекта" - https://ru.wikipedia.org/wiki/Божественный_объект
#API #arch #tracing
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые типы потребителей. О версионировании нужно подумать заранее.
2) Сервер и клиенты поддерживают работу с несколькими версиями API. Это позволит избежать синхронных внедрений двух и более микросервисов. Синхронное внедрение - это сложно и повышает вероятность нарушить все наши "девятки" (SLA)
3) API описано схемой. Король горы для REST запросов - OpenAPI. Отмечу, что в отличие от JSON Schema или XSD OpenAPI описывает не модель данных, а web сервис целиком: поддерживаемые HTTP методы - GET, POST,..., коды ответов HTTP, параметры запроса, заголовки.
4) CDC тестирование - https://martinfowler.com/articles/consumerDrivenContracts.html#Consumer-drivenContracts
В чем суть: создается контракт - человеко и машиночитаемое описание тест-кейсов для API, на основании которых генерируются API тесты для поставщика и потребителя. Примеры реализаций:
Spring Cloud Contract https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/getting-started.html#getting-started-three-second-tour
Pact https://docs.pact.io/5-minute-getting-started-guide
Надо отметить, что OpenAPI и CDS в ряде моментов дублируют информацию, об этой проблеме и возможном решении для Spring можно почитать тут: https://springframework.guru/defining-spring-cloud-contracts-in-open-api/
5) API должно предусматривать уникальный идентификатор запроса, обеспечивающий идемпотентность - возможность повторного вызова метода API, не приводящего к дублированию данных на сервере. В сети и на сервере случаются сбои, повтор вызова в этом случае - естественный выход из ситуации. При получении второго и последующего запросов сервер, определив по уникальному идентификатору, что он уже получал этот запрос, должен вернуть текущий статус операции
6) API должно содержать trace_id - уникальный идентификатор операции. trace_id генерируется на клиенте и копируется в каждый последующий запрос по всем микросервисам. Потом с помощью таких инструментов, как Jaeger дерево запросов визуализируется, что упрощает отлавливание ошибок
7) в API не должно быть ничего лишнего. Добавляем то, что нужно клиенту, если появляется новые требования - версионируем API. Иначе получим аналог "божественного объекта" - https://ru.wikipedia.org/wiki/Божественный_объект
#API #arch #tracing
martinfowler.com
Consumer-Driven Contracts: A Service Evolution
Pattern
Pattern
Consumers should drive the definition of service contracts, while limiting to their individual needs. Suppliers should then validate against the union of their consumers' contracts.
Всем привет!
Сегодня короткое ревью на книжку Непрерывное развитие API. https://habr.com/ru/company/piter/blog/472522/
Несмотря на многообещающее название - не понравилась.
Слишком менеджерская и "капитанская".
По технике практически ноль.
Приведу несколько идей, достаточно полезных, чтобы примерно было понятно, о чем речь:
1) рассматривайте API как продукт, есть компании, где API - единственный продукт: Twillo, Stripe
2) в первую версию API надо вкладывать больше усилий, потом можно ее непрерывно улучшать небольшими шагами, Lean, Agile, все как мы любим)
3) документация для API важна, особенно примеры использования, также для больших организаций полезен реестр API и инструменты для тестирования типа тех, что предоставляет Swagger https://editor.swagger.io/
4) тестируйте создаваемое API со стороны клиента, это поможет лучше его спроектировать
5) мониторьте боевые сервера API как на предмет ошибок, так и для сбора общей статистики по числу запросов, времени выполенния, типичным последовательностям запросов. Возможно постоянно повторяющиеся последовательности вызовов можно заменить одним.
6) с ростом организации централизовано реализовывать API невозможно, поэтому большУю часть решений нужно отдавать в команды. Централизовано имеет смысл отбирать список допустимых протоколов\технологий, и, возможно, согласование и тестирование API
7) ключевые решения по API должны примимать опытные разработчики
8) во внешнее API стоит вкладывать больше усилий, чем во внутреннее
9) автоматизация тестирования API требует больших затрат на разработку и поддержку как и любая автоматизация, но в целом полезна
10) API должно помогать достижению целей организации, можно использовать KPI и OKR для определения, достигает ли API поставленных целей. Вот на этом шаге и бросил читать)
Итого: верхнеуровнево есть правильные мысли, но с практическая ценность маленькая. Не рекомендую.
#books #api
Сегодня короткое ревью на книжку Непрерывное развитие API. https://habr.com/ru/company/piter/blog/472522/
Несмотря на многообещающее название - не понравилась.
Слишком менеджерская и "капитанская".
По технике практически ноль.
Приведу несколько идей, достаточно полезных, чтобы примерно было понятно, о чем речь:
1) рассматривайте API как продукт, есть компании, где API - единственный продукт: Twillo, Stripe
2) в первую версию API надо вкладывать больше усилий, потом можно ее непрерывно улучшать небольшими шагами, Lean, Agile, все как мы любим)
3) документация для API важна, особенно примеры использования, также для больших организаций полезен реестр API и инструменты для тестирования типа тех, что предоставляет Swagger https://editor.swagger.io/
4) тестируйте создаваемое API со стороны клиента, это поможет лучше его спроектировать
5) мониторьте боевые сервера API как на предмет ошибок, так и для сбора общей статистики по числу запросов, времени выполенния, типичным последовательностям запросов. Возможно постоянно повторяющиеся последовательности вызовов можно заменить одним.
6) с ростом организации централизовано реализовывать API невозможно, поэтому большУю часть решений нужно отдавать в команды. Централизовано имеет смысл отбирать список допустимых протоколов\технологий, и, возможно, согласование и тестирование API
7) ключевые решения по API должны примимать опытные разработчики
8) во внешнее API стоит вкладывать больше усилий, чем во внутреннее
9) автоматизация тестирования API требует больших затрат на разработку и поддержку как и любая автоматизация, но в целом полезна
10) API должно помогать достижению целей организации, можно использовать KPI и OKR для определения, достигает ли API поставленных целей. Вот на этом шаге и бросил читать)
Итого: верхнеуровнево есть правильные мысли, но с практическая ценность маленькая. Не рекомендую.
#books #api
Хабр
Книга «Непрерывное развитие API. Правильные решения в изменчивом технологическом ландшафте»
Для реализации API необходимо провести большую работу. Чрезмерное планирование может стать пустой тратой сил, а его недостаток приводит к катастрофическим последствиям. В этой книге вы получите...
Всем привет!
Что такое REST? Чтобы не увеличивать энтропию в сети я дам ссылку на хорошую статью про REST - https://habr.com/ru/post/590679/
Но как всегда попробую сделать из нее краткие выводы)))
Основные заблуждения касаемо REST:
1) REST - это не протокол, а парадигма при создании API. Большинство требований REST не относятся к протоколу (HTTP)
2) JSON не является обязательным для REST, просто большинство REST API используют JSON
3) нельзя сказать, что если мы не используем HTTP глаголы или продумали концепцию REST ресурсов - это не REST. Есть 4 уровня зрелости REST, https://habrastorage.org/getpro/habr/upload_files/bd8/e4b/848/bd8e4b8488e0085b7404a37dc93faf6c.png Выставляя API в виде набора HTTP POST запросов, мы находимся на 1-м уровне зрелости. Добавляем концепцию ресурсов, выраженных в HTTP path - 2-й уровень. HTTP глаголы - 3-й уровень. А 4-й - это такая интересная штука, как HATEOS. Детали: https://habr.com/ru/post/483328/ Кто-то его видел в живой природе, кстати?
4) REST не означает, что про валидацию по схеме можно забыть. Тот же OpenAPI - очень хорош, и позволяет достаточно гибко настроить схему и описать протокол взаимодействия.
Важные замечания:
1) REST по определению должен быть stateless. Как это понимать? Я скажу так: если мы привязываем клиента к конкретному серверу - это уже не stateless. Что значит привязываем? Это значит мы закэшировали что-то важное на этом конкретном сервере. И при выходе из строя этого сервера текущий процесс клиента ломается, например, ему приходится перелогинится или он потеряет введенные данные. Т.е. использование sticky session для оптимизации - не отменяет REST.
2) stateless не значит хранить все на клиенте - в куках или в кэше МП. Куки, к слову, вообще не предназначены для хранения больших объемов данных, т.к. передаются при каждом запросе и неустойчивы к взлому. Кроме того, хранение данных на клиенте чувствительно к его сбоям, не омниканально и усложняет процесс обновления клиента, т.к. приходится обновлять и его кэш. Хранить состояние нужно либо в БД, либо в расределенном кэше
3) stateless критически важно не потому, что идеолог REST написал так в своей статье) stateless дает нам легкое горизонтальное масштабирование с помощью k8s
4) не везде об этом говорится, но исходя из идеи прозрачности REST - по возможности стоит переиспользовать коды ошибок протокола HTTP. Их кстати довольно много https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP Хотя все равно может не хватить в вашем конкретном случае, тогда можно расширить список кодов через body
#REST #API #http
Что такое REST? Чтобы не увеличивать энтропию в сети я дам ссылку на хорошую статью про REST - https://habr.com/ru/post/590679/
Но как всегда попробую сделать из нее краткие выводы)))
Основные заблуждения касаемо REST:
1) REST - это не протокол, а парадигма при создании API. Большинство требований REST не относятся к протоколу (HTTP)
2) JSON не является обязательным для REST, просто большинство REST API используют JSON
3) нельзя сказать, что если мы не используем HTTP глаголы или продумали концепцию REST ресурсов - это не REST. Есть 4 уровня зрелости REST, https://habrastorage.org/getpro/habr/upload_files/bd8/e4b/848/bd8e4b8488e0085b7404a37dc93faf6c.png Выставляя API в виде набора HTTP POST запросов, мы находимся на 1-м уровне зрелости. Добавляем концепцию ресурсов, выраженных в HTTP path - 2-й уровень. HTTP глаголы - 3-й уровень. А 4-й - это такая интересная штука, как HATEOS. Детали: https://habr.com/ru/post/483328/ Кто-то его видел в живой природе, кстати?
4) REST не означает, что про валидацию по схеме можно забыть. Тот же OpenAPI - очень хорош, и позволяет достаточно гибко настроить схему и описать протокол взаимодействия.
Важные замечания:
1) REST по определению должен быть stateless. Как это понимать? Я скажу так: если мы привязываем клиента к конкретному серверу - это уже не stateless. Что значит привязываем? Это значит мы закэшировали что-то важное на этом конкретном сервере. И при выходе из строя этого сервера текущий процесс клиента ломается, например, ему приходится перелогинится или он потеряет введенные данные. Т.е. использование sticky session для оптимизации - не отменяет REST.
2) stateless не значит хранить все на клиенте - в куках или в кэше МП. Куки, к слову, вообще не предназначены для хранения больших объемов данных, т.к. передаются при каждом запросе и неустойчивы к взлому. Кроме того, хранение данных на клиенте чувствительно к его сбоям, не омниканально и усложняет процесс обновления клиента, т.к. приходится обновлять и его кэш. Хранить состояние нужно либо в БД, либо в расределенном кэше
3) stateless критически важно не потому, что идеолог REST написал так в своей статье) stateless дает нам легкое горизонтальное масштабирование с помощью k8s
4) не везде об этом говорится, но исходя из идеи прозрачности REST - по возможности стоит переиспользовать коды ошибок протокола HTTP. Их кстати довольно много https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP Хотя все равно может не хватить в вашем конкретном случае, тогда можно расширить список кодов через body
#REST #API #http
Хабр
REST, что же ты такое? Понятное введение в технологию для ИТ-аналитиков
Мы подготовили статью Андрея Буракова на основе его вебинара на нашем YouTube-канале: Проектирование и работа с REST-сервисами стали повседневными задачами для многих аналитиков. Однако мы часто...
Всем привет!
В протоколе HTTP, а также gRPC, основанном на HTTP/2, есть возможность передачи параметров запроса разными способами:
1) в заголовках
2) в параметрах
3) в path части url
4) в теле запроса
Когда что использовать? Ниже будут типовые варианты, в реальных кейсах конечно же возможны отклонения.
1) headers - не бизнесовые, технические данные. Примеры: id для tracing, для логирования, маршрутизации, токены\куки для авторизации. Ключевой момент - в бизнес-процессе эти данные не используются
2) params - как правило используются в GET запросах, по сути фильтр для выборки данных
3) path - как правило в REST запросе, построенном на концепции REST ресурсов, для идентификации ресурса: GET\PUT\DELETE .../order/{nnn}
4) body - атрибуты объекта для создания\обновления в REST. Любая закрытая информация - https шифрует заголовки и тело запроса, но само собой не шифрует параметры и путь. Большие объемы данных, в URL есть ограничения на длину, причем в разных браузерах и проксях они разные, лучше к ним не приближаться). По объему данных в заголовках также есть ограничения на веб-серверах, привет "413 Entity Too Large". Размер можно подкрутить в большую сторону, но опять же это не наш метод)
#rest #api
В протоколе HTTP, а также gRPC, основанном на HTTP/2, есть возможность передачи параметров запроса разными способами:
1) в заголовках
2) в параметрах
3) в path части url
4) в теле запроса
Когда что использовать? Ниже будут типовые варианты, в реальных кейсах конечно же возможны отклонения.
1) headers - не бизнесовые, технические данные. Примеры: id для tracing, для логирования, маршрутизации, токены\куки для авторизации. Ключевой момент - в бизнес-процессе эти данные не используются
2) params - как правило используются в GET запросах, по сути фильтр для выборки данных
3) path - как правило в REST запросе, построенном на концепции REST ресурсов, для идентификации ресурса: GET\PUT\DELETE .../order/{nnn}
4) body - атрибуты объекта для создания\обновления в REST. Любая закрытая информация - https шифрует заголовки и тело запроса, но само собой не шифрует параметры и путь. Большие объемы данных, в URL есть ограничения на длину, причем в разных браузерах и проксях они разные, лучше к ним не приближаться). По объему данных в заголовках также есть ограничения на веб-серверах, привет "413 Entity Too Large". Размер можно подкрутить в большую сторону, но опять же это не наш метод)
#rest #api
Всем привет!
Во-первых поздравляю всех с Днем Победы!
Но совсем без разработки в посте я не могу)
Поэтому вернемся к разговору про API.
Давно хотел написать про важность идемпотентности API, о которой упоминал в https://t.me/javaKotlinDevOps/24
Но меня опередили https://habr.com/ru/companies/yandex/articles/442762/
Причем добавить по большому счету нечего, кроме пары замечаний.
Первое - лучше не пытаться решить проблему повторных заказов и таймаутов на клиентской стороне.
Основные проверки должны быть на сервере, на клиенте - дополнительные, улучшающие клиентский опыт.
Ну и второй момент - правильность реализации идемпотентности невозможно проверить автоматически, достаточно сложно - автотестами. Очень важен процесс код-ревью.
#api
Во-первых поздравляю всех с Днем Победы!
Но совсем без разработки в посте я не могу)
Поэтому вернемся к разговору про API.
Давно хотел написать про важность идемпотентности API, о которой упоминал в https://t.me/javaKotlinDevOps/24
Но меня опередили https://habr.com/ru/companies/yandex/articles/442762/
Причем добавить по большому счету нечего, кроме пары замечаний.
Первое - лучше не пытаться решить проблему повторных заказов и таймаутов на клиентской стороне.
Основные проверки должны быть на сервере, на клиенте - дополнительные, улучшающие клиентский опыт.
Ну и второй момент - правильность реализации идемпотентности невозможно проверить автоматически, достаточно сложно - автотестами. Очень важен процесс код-ревью.
#api
Telegram
(java || kotlin) && devOps
Всем привет!
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые…
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые…
Всем привет!
Я упоминал в посте про JMS vs Kafka про ESB - Enterprise Service Bus. Она же Корпоративная Сервисная Шина.
Какие плюсы и минусы данного решения?
Плюсов я вижу три:
1) унификация API в пределах компании
2) единая точка мониторинга и контроля всех интеграций
3) больше возможностей для переиспользования уже существующих API
Минусы такие:
1) т.к. ESB - это отдельная система, то ее разрабатывает как правило отдельная команда, которая быстро становится узким местом. Особенно при внедрении микросервисной архитектуры и резком увеличении числа интеграций
2) ESB как правило вносит дополнительные задержки, что особенно критично при синхронном взаимодействии
3) как правило ESB предлагают коммерческие компании, что приводит к vendor lock. Слезть с такого решения будет сложно
4) неочевидная штука - с одной стороны команда ESB унифицирует все API. Но с другой - API становятся перегруженными. Там будут какие-то стандартизированные для всех поля, общие базовые типы, которые во многих случаях будут избыточными
5) также ESB из-за стандартизации затрудняет развитие API. Т.к. унификация, а кроме того больше команд участвует в согласовании - три вместо двух
Вывод: на данном этапе развития ПО идея ESB выглядит избыточной.
Но что же с плюсами, как добиться того же результата с API точка-точка и микросервисной архитектурой?
1) унификация вещь полезная, главное чтобы она не была избыточной. Архитектор может выставить требования по API, DevOps - встроить их проверку в pipeline.
2) единая точка контроля - в случае облачной среды такой точкой может быть Istio или k8s. Либо ставить proxy на границах сред.
3) для переиспользования можно использовать каталог API. Да и не всегда переиспользование полезно, см. выше про избыточное API. Также отдельное API для каждого потребителя позволяет лучше контролировать доступ к данным
#api #esb
Я упоминал в посте про JMS vs Kafka про ESB - Enterprise Service Bus. Она же Корпоративная Сервисная Шина.
Какие плюсы и минусы данного решения?
Плюсов я вижу три:
1) унификация API в пределах компании
2) единая точка мониторинга и контроля всех интеграций
3) больше возможностей для переиспользования уже существующих API
Минусы такие:
1) т.к. ESB - это отдельная система, то ее разрабатывает как правило отдельная команда, которая быстро становится узким местом. Особенно при внедрении микросервисной архитектуры и резком увеличении числа интеграций
2) ESB как правило вносит дополнительные задержки, что особенно критично при синхронном взаимодействии
3) как правило ESB предлагают коммерческие компании, что приводит к vendor lock. Слезть с такого решения будет сложно
4) неочевидная штука - с одной стороны команда ESB унифицирует все API. Но с другой - API становятся перегруженными. Там будут какие-то стандартизированные для всех поля, общие базовые типы, которые во многих случаях будут избыточными
5) также ESB из-за стандартизации затрудняет развитие API. Т.к. унификация, а кроме того больше команд участвует в согласовании - три вместо двух
Вывод: на данном этапе развития ПО идея ESB выглядит избыточной.
Но что же с плюсами, как добиться того же результата с API точка-точка и микросервисной архитектурой?
1) унификация вещь полезная, главное чтобы она не была избыточной. Архитектор может выставить требования по API, DevOps - встроить их проверку в pipeline.
2) единая точка контроля - в случае облачной среды такой точкой может быть Istio или k8s. Либо ставить proxy на границах сред.
3) для переиспользования можно использовать каталог API. Да и не всегда переиспользование полезно, см. выше про избыточное API. Также отдельное API для каждого потребителя позволяет лучше контролировать доступ к данным
#api #esb
Всем привет!
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий. Но есть нюанс. Схема OpenAPI - внешний артефакт. Он лежит либо в git репозитории или API Studio от Swagger. Код по нему генерируется в каталоге сборки. Забыть обновится при выходе новой версии сложнее как раз из-за чёткого понимания того, что API - внешнее. Хотя конечно же можно )
Другое дело Java API. Это про сути ещё одна из десятков библиотек, подключенных к проекту. Версию библиотеки мы фиксируем как это принято при управлении зависимостями. Забыть о том, что это внешнее API, гораздо легче.
Я сейчас говорю не только про кейс, описанный в статье. Ещё есть вариант обмена данными через распределенный кэш, путём сериализации Java POJO объектов, встречал его на практике. А самый яркий антипаттерн при похожем подходе - обмен данными через БД. В этом случае как правило обмениваются скриптами БД, а не классами. Но идея похожа - зачем нам лишняя сущность в виде схемы, лишние преобразования, когда уже есть код. Или уже есть таблица в БД. Конечно, интеграция через БД стала антипаттерном в том числе и потому, что БД - это не только схема, но ещё и транзакции, блокировки, триггеры. Но главную причину я озвучил выше - каждая команда будет считать базу своей внутренней, забывая, что это API. Проблема психологическая, не техническая.
Итого: подход интересный, имеет права на жизнь (я про обмен jar-никами, не про интеграцию через БД), но требует дисциплины. Или автоматизации на этапе CI, позволяющей не надеятся на человеческий фактор.
P.S. Как говорится, не OpenAPI единым - есть ещё Protobuf, GraphQL, xsd наконец. Но самый распространённый - OpenAPI, поэтому везде упоминается он.
#api #OpenAPI #integration
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий. Но есть нюанс. Схема OpenAPI - внешний артефакт. Он лежит либо в git репозитории или API Studio от Swagger. Код по нему генерируется в каталоге сборки. Забыть обновится при выходе новой версии сложнее как раз из-за чёткого понимания того, что API - внешнее. Хотя конечно же можно )
Другое дело Java API. Это про сути ещё одна из десятков библиотек, подключенных к проекту. Версию библиотеки мы фиксируем как это принято при управлении зависимостями. Забыть о том, что это внешнее API, гораздо легче.
Я сейчас говорю не только про кейс, описанный в статье. Ещё есть вариант обмена данными через распределенный кэш, путём сериализации Java POJO объектов, встречал его на практике. А самый яркий антипаттерн при похожем подходе - обмен данными через БД. В этом случае как правило обмениваются скриптами БД, а не классами. Но идея похожа - зачем нам лишняя сущность в виде схемы, лишние преобразования, когда уже есть код. Или уже есть таблица в БД. Конечно, интеграция через БД стала антипаттерном в том числе и потому, что БД - это не только схема, но ещё и транзакции, блокировки, триггеры. Но главную причину я озвучил выше - каждая команда будет считать базу своей внутренней, забывая, что это API. Проблема психологическая, не техническая.
Итого: подход интересный, имеет права на жизнь (я про обмен jar-никами, не про интеграцию через БД), но требует дисциплины. Или автоматизации на этапе CI, позволяющей не надеятся на человеческий фактор.
P.S. Как говорится, не OpenAPI единым - есть ещё Protobuf, GraphQL, xsd наконец. Но самый распространённый - OpenAPI, поэтому везде упоминается он.
#api #OpenAPI #integration
Хабр
Объектно-ориентированный подход к созданию REST-клиентов, или возможна ли жизнь без Open API
Как-то в общении с моим другом-разработчиком из одной крупной софтверной компании у нас зашёл разговор о взаимодействии распределённых команд. В его компании было множество достаточно изолированных...
Всем привет!
Наверное вы слышали про такой стандарт 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: 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
Наверное вы слышали про такой стандарт 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.org
GraphQL | A query language for your API
Всем привет!
Самая крутая фича 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
Самая крутая фича 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
Примерный набор команд:
git config submodule.recurse true # добавляет ключ --recurse-submodules ко всем командам кроме clone. В частности checkout и pull
git config diff.submodule log # отображать также изменения в подмодулях при выполнении diff в корне
git config alias.clones 'clone --recurse-submodules' # подтягивать подмодули при клонировании
git config alias.diffs '!'"git diff && git submodule foreach 'git diff'" # показать изменения по всем подмодулям
git config alias.pushs 'push --recurse-submodules=on-demand' # запушить изменения вначале в подмодулях, потом в основной проект
git config alias.updates 'submodule update --remote --merge' # подтянуть изменения подмодулей из удаленных репозиториев и влить их в локальную копию. После этого можно самому вносить изменения в подмодуль
В любом случае предлагаю прочитать статью по ссылке выше.
#git #api #integraion
git config submodule.recurse true # добавляет ключ --recurse-submodules ко всем командам кроме clone. В частности checkout и pull
git config diff.submodule log # отображать также изменения в подмодулях при выполнении diff в корне
git config alias.clones 'clone --recurse-submodules' # подтягивать подмодули при клонировании
git config alias.diffs '!'"git diff && git submodule foreach 'git diff'" # показать изменения по всем подмодулям
git config alias.pushs 'push --recurse-submodules=on-demand' # запушить изменения вначале в подмодулях, потом в основной проект
git config alias.updates 'submodule update --remote --merge' # подтянуть изменения подмодулей из удаленных репозиториев и влить их в локальную копию. После этого можно самому вносить изменения в подмодуль
В любом случае предлагаю прочитать статью по ссылке выше.
#git #api #integraion
Telegram
(java || kotlin) && devOps
Всем привет!
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий.…
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий.…