1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-05-25 22:08:06 +02:00

Fix typos

This commit is contained in:
Pavel Bychko 2023-05-18 23:48:43 +03:00
parent fd010e2c1f
commit e937d1e3ee
34 changed files with 54 additions and 54 deletions

View File

@ -4539,7 +4539,7 @@ ProgramContext.dispatch = (action) => {
<p>Исходя из вышесказанного, примеры кода — самый важный инструмент привлечения и поддержки новых пользователей вашего API. Исключительно важно подобрать примеры так, чтобы они облегчали новичкам работу с API; неправильно выстроенные примеры только ухудшат качество вашей документации. При составлении примеров следует руководствоваться следующими принципами:</p>
<ul>
<li>примеры должны покрывать актуальные сценарии использования API: чем лучше вы угадаете наиболее частые запросы разработчиков, тем более дружелюбным и простым для входа будет выглядеть ваш API в их глазах;</li>
<li>примеры должны быть лаконичными и атомарными: cмешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;</li>
<li>примеры должны быть лаконичными и атомарными: смешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;</li>
<li>код примеров должен быть максимально приближен к реальному приложению; автор этой книги сталкивался с ситуацией, когда синтетический фрагмент кода, абсолютно бессмысленный в реальном мире, был бездумно растиражирован разработчиками в огромном количестве.</li>
</ul>
<p>В идеале примеры должны быть провязаны со всеми остальными видами документации. В частности, референс должен содержать примеры, релевантные описанию сущностей.</p>

View File

@ -42,7 +42,7 @@
<br />Поддержите эту работу на <a class="patreon" href="https://www.patreon.com/yatwirl">Patreon</a>
<br />Поделиться: <a class="share share-facebook" href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Ftwirl.github.io%2FThe-API-Book%2Findex.ru.html" target="_blank"></a> · <a class="share share-twitter" href="https://twitter.com/intent/tweet?text=%C2%ABAPI%C2%BB%20%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D1%8F%20%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82%D0%B8%D0%BD%D0%BE%D0%B2%D0%B0%20%E2%80%94%20%D0%BA%D0%BD%D0%B8%D0%B3%D0%B0%20%D0%BE%20%D0%B4%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD%D0%B5%20API%20%D0%B8%20%D0%B5%D0%B3%D0%BE%20%D0%BF%D1%80%D0%BE%D0%B4%D1%83%D0%BA%D1%82%D0%BE%D0%B2%D0%BE%D0%BC%20%D0%B8%20%D1%82%D0%B5%D1%85%D0%BD%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC%20%D1%80%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B8&url=https%3A%2F%2Ftwirl.github.io%2FThe-API-Book%2Findex.ru.html&hashtags=API%2CTheAPIBook&via=blogovodoved" target="_blank"></a> · <a class="share share-linkedin" href="https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Ftwirl.github.io%2FThe-API-Book%2Findex.ru.html" target="_blank"></a> · <a class="share share-reddit" href="http://www.reddit.com/submit?url=https%3A%2F%2Ftwirl.github.io%2FThe-API-Book%2Findex.ru.html&title=%C2%ABAPI%C2%BB%20%D0%A1%D0%B5%D1%80%D0%B3%D0%B5%D1%8F%20%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D0%B0%D0%BD%D1%82%D0%B8%D0%BD%D0%BE%D0%B2%D0%B0%20%E2%80%94%20%D0%BA%D0%BD%D0%B8%D0%B3%D0%B0%20%D0%BE%20%D0%B4%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD%D0%B5%20API%20%D0%B8%20%D0%B5%D0%B3%D0%BE%20%D0%BF%D1%80%D0%BE%D0%B4%D1%83%D0%BA%D1%82%D0%BE%D0%B2%D0%BE%D0%BC%20%D0%B8%20%D1%82%D0%B5%D1%85%D0%BD%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%BC%20%D1%80%D0%B0%D0%B7%D0%B2%D0%B8%D1%82%D0%B8%D0%B8" target="_blank"></a><br/>⚙️⚙️⚙️
</nav>
<p>«API-first» подход — одна из самых горячих горячих тем в разработке программного обеспечения в наше время. Многие компании начали понимать, что API выступает мультипликатором их возможностей — но также умножает и допущенные ошибки.</p>
<p>«API-first» подход — одна из самых горячих тем в разработке программного обеспечения в наше время. Многие компании начали понимать, что API выступает мультипликатором их возможностей — но также умножает и допущенные ошибки.</p>
<p>Эта книга написана для того, чтобы поделиться опытом и изложить лучшие практики разработки API. Книга состоит из шести разделов, посвящённых:</p>
<ul><li>— проектированию API,</li>
<li>— паттернам дизайна API,</li>
@ -57,9 +57,9 @@
<ul><li>
<h4><a href="API.ru.html#section-1">Введение</a></h4>
<ul>
<li><a href="API.ru.html#intro-structure">Глава 1. О структуре этой книги</a></li>
<li><a href="API.ru.html#intro-structure">Глава 1. О структуре этой книги</a></li>
<li><a href="API.ru.html#intro-api-definition">Глава 2. Определение API</a></li>
<li><a href="API.ru.html#intro-api-solutions-overview">Глава 3. Обзор существующих решений в области разработки API</a></li>
<li><a href="API.ru.html#intro-api-solutions-overview">Глава 3. Обзор существующих решений в области разработки API</a></li>
<li><a href="API.ru.html#intro-api-quality">Глава 4. Критерии качества API</a></li>
<li><a href="API.ru.html#intro-api-first-approach">Глава 5. API-first подход</a></li>
<li><a href="API.ru.html#intro-back-compat">Глава 6. Обратная совместимость</a></li>
@ -72,10 +72,10 @@
<ul>
<li><a href="API.ru.html#api-design-context-pyramid">Глава 9. Пирамида контекстов API</a></li>
<li><a href="API.ru.html#api-design-defining-field">Глава 10. Определение области применения</a></li>
<li><a href="API.ru.html#api-design-separating-abstractions">Глава 11. Разделение уровней абстракции</a></li>
<li><a href="API.ru.html#api-design-isolating-responsibility">Глава 12. Разграничение областей ответственности</a></li>
<li><a href="API.ru.html#api-design-describing-interfaces">Глава 13. Описание конечных интерфейсов</a></li>
<li><a href="API.ru.html#api-design-annex">Глава 14. Приложение к разделу I. Модельный API</a></li>
<li><a href="API.ru.html#api-design-separating-abstractions">Глава 11. Разделение уровней абстракции</a></li>
<li><a href="API.ru.html#api-design-isolating-responsibility">Глава 12. Разграничение областей ответственности</a></li>
<li><a href="API.ru.html#api-design-describing-interfaces">Глава 13. Описание конечных интерфейсов</a></li>
<li><a href="API.ru.html#api-design-annex">Глава 14. Приложение к разделу I. Модельный API</a></li>
</ul>
</li>
<li>
@ -88,7 +88,7 @@
<li><a href="API.ru.html#api-patterns-async">Глава 19. Асинхронность и управление временем</a></li>
<li><a href="API.ru.html#api-patterns-lists">Глава 20. Списки и организация доступа к ним</a></li>
<li><a href="API.ru.html#api-patterns-push-vs-poll">Глава 21. Двунаправленные потоки данных. Push и poll-модели</a></li>
<li><a href="API.ru.html#api-patterns-async-event-processing">Глава 22. Мультиплексирование сообщений. Асинхронная обработка событий</a></li>
<li><a href="API.ru.html#api-patterns-async-event-processing">Глава 22. Мультиплексирование сообщений. Асинхронная обработка событий</a></li>
<li><a href="API.ru.html#chapter-23">Глава 23. Атомарность</a></li>
<li><a href="API.ru.html#chapter-24">Глава 24. Частичные обновления</a></li>
<li><a href="API.ru.html#chapter-25">Глава 25. Деградация и предсказуемость</a></li>
@ -97,12 +97,12 @@
<li>
<h4><a href="API.ru.html#section-4">Раздел III. Обратная совместимость</a></h4>
<ul>
<li><a href="API.ru.html#back-compat-statement">Глава 26. Постановка проблемы обратной совместимости</a></li>
<li><a href="API.ru.html#back-compat-iceberg-waterline">Глава 27. О ватерлинии айсберга</a></li>
<li><a href="API.ru.html#back-compat-statement">Глава 26. Постановка проблемы обратной совместимости</a></li>
<li><a href="API.ru.html#back-compat-iceberg-waterline">Глава 27. О ватерлинии айсберга</a></li>
<li><a href="API.ru.html#back-compat-abstracting-extending">Глава 28. Расширение через абстрагирование</a></li>
<li><a href="API.ru.html#back-compat-strong-coupling">Глава 29. Сильная связность и сопутствующие проблемы</a></li>
<li><a href="API.ru.html#back-compat-weak-coupling">Глава 30. Слабая связность</a></li>
<li><a href="API.ru.html#back-compat-universal-interfaces">Глава 31. Интерфейсы как универсальный паттерн</a></li>
<li><a href="API.ru.html#back-compat-universal-interfaces">Глава 31. Интерфейсы как универсальный паттерн</a></li>
<li><a href="API.ru.html#back-compat-serenity-notepad">Глава 32. Блокнот душевного покоя</a></li>
</ul>
</li>
@ -115,7 +115,7 @@
<li><a href="API.ru.html#chapter-36">Глава 36. Преимущества и недостатки HTTP API</a></li>
<li><a href="API.ru.html#chapter-37">Глава 37. Принципы организации HTTP API</a></li>
<li><a href="API.ru.html#chapter-38">Глава 38. Работа с ошибками в HTTP API</a></li>
<li><a href="API.ru.html#chapter-39">Глава 39. Организация URL ресурсов и операций над ними в HTTP API</a></li>
<li><a href="API.ru.html#chapter-39">Глава 39. Организация URL ресурсов и операций над ними в HTTP API</a></li>
<li><a href="API.ru.html#chapter-40">Глава 40. Заключительные положения и общие рекомендации</a></li>
</ul>
</li>
@ -130,7 +130,7 @@
<li><a href="API.ru.html#chapter-46">Глава 46. MV*-фреймворки</a></li>
<li><a href="API.ru.html#chapter-47">Глава 47. Backend-Driven UI</a></li>
<li><a href="API.ru.html#chapter-48">Глава 48. Разделяемые ресурсы и асинхронные блокировки</a></li>
<li><a href="API.ru.html#chapter-49">Глава 49. Вычисляемые свойства</a></li>
<li><a href="API.ru.html#chapter-49">Глава 49. Вычисляемые свойства</a></li>
<li><a href="API.ru.html#chapter-50">Глава 50. В заключение</a></li>
</ul>
</li>
@ -140,13 +140,13 @@
<li><a href="API.ru.html#api-product">Глава 51. Продукт API</a></li>
<li><a href="API.ru.html#api-product-business-models">Глава 52. Бизнес-модели API</a></li>
<li><a href="API.ru.html#api-product-vision">Глава 53. Формирование продуктового видения</a></li>
<li><a href="API.ru.html#api-product-devrel">Глава 54. Взаимодействие с разработчиками</a></li>
<li><a href="API.ru.html#api-product-business-comms">Глава 55. Взаимодействие с бизнес-аудиторией</a></li>
<li><a href="API.ru.html#api-product-range">Глава 56. Линейка сервисов API</a></li>
<li><a href="API.ru.html#api-product-devrel">Глава 54. Взаимодействие с разработчиками</a></li>
<li><a href="API.ru.html#api-product-business-comms">Глава 55. Взаимодействие с бизнес-аудиторией</a></li>
<li><a href="API.ru.html#api-product-range">Глава 56. Линейка сервисов API</a></li>
<li><a href="API.ru.html#api-product-kpi">Глава 57. Ключевые показатели эффективности API</a></li>
<li><a href="API.ru.html#api-product-antifraud">Глава 58. Идентификация пользователей и борьба с фродом</a></li>
<li><a href="API.ru.html#api-product-antifraud">Глава 58. Идентификация пользователей и борьба с фродом</a></li>
<li><a href="API.ru.html#api-product-tos-violations">Глава 59. Технические способы борьбы с несанкционированным доступом к API</a></li>
<li><a href="API.ru.html#api-product-customer-support">Глава 60. Поддержка пользователей API</a></li>
<li><a href="API.ru.html#api-product-customer-support">Глава 60. Поддержка пользователей API</a></li>
<li><a href="API.ru.html#api-product-documentation">Глава 61. Документация</a></li>
<li><a href="API.ru.html#api-product-testing">Глава 62. Тестовая среда</a></li>
<li><a href="API.ru.html#api-product-expectations">Глава 63. Управление ожиданиями</a></li>
@ -160,7 +160,7 @@
<aside><img src="https://konstantinov.cc/static/me.png"/><br/>Фото: <a href="http://linkedin.com/in/zloylos/">Denis Hananein</a></aside>
<div class="content">
<p>Сергей Константинов работает с API уже больше десятилетия. Он начинал свою карьеру разработчиком в подразделении API Яндекс.Карт, и со временем стал руководителем всего сервиса, отвечая и за техническую, и за продуктовую составляющую.</p>
<p>За это время Сергей получил уникальный опыт построения API мирового уровня с дневной аудторией в десятки миллионов человек, планирования роадмапов для такого продукта и многочисленных публичных выступлений. Он также проработал полтора года в составе Технической архитектурной группы W3C.</p>
<p>За это время Сергей получил уникальный опыт построения API мирового уровня с дневной аудиторией в десятки миллионов человек, планирования роадмапов для такого продукта и многочисленных публичных выступлений. Он также проработал полтора года в составе Технической архитектурной группы W3C.</p>
<p>После девяти лет в Картах Сергей переключился на технические роли в других департаментах и компаниях, занимаясь интеграционными проектами и будучи ответственным за техническую архитектуру целых продуктов компании. Сегодня Сергей живёт в Таллинне, Эстония, и работает ведущим инженером в компании Bolt.</p></div>
</section>
<p>You might also <a href="index.html">read ‘The API’ in English</a>.</p>

View File

@ -3906,7 +3906,7 @@ ProgramContext.dispatch = (action) => {
<p>Исходя из вышесказанного, примеры кода — самый важный инструмент привлечения и поддержки новых пользователей вашего API. Исключительно важно подобрать примеры так, чтобы они облегчали новичкам работу с API; неправильно выстроенные примеры только ухудшат качество вашей документации. При составлении примеров следует руководствоваться следующими принципами:</p>
<ul>
<li>примеры должны покрывать актуальные сценарии использования API: чем лучше вы угадаете наиболее частые запросы разработчиков, тем более дружелюбным и простым для входа будет выглядеть ваш API в их глазах;</li>
<li>примеры должны быть лаконичными и атомарными: cмешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;</li>
<li>примеры должны быть лаконичными и атомарными: смешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;</li>
<li>код примеров должен быть максимально приближен к реальному приложению; автор этой книги сталкивался с ситуацией, когда синтетический фрагмент кода, абсолютно бессмысленный в реальном мире, был бездумно растиражирован разработчиками в огромном количестве.</li>
</ul>
<p>В идеале примеры должны быть провязаны со всеми остальными видами документации. В частности, референс должен содержать примеры, релевантные описанию сущностей.</p>

View File

@ -16,7 +16,7 @@
* либо клиент-серверное взаимодействие опирается на описанные в стандарте HTTP возможности (точнее было бы сказать, «стандартах HTTP», поскольку функциональность протокола описана во множестве разных RFC);
* либо HTTP утилизируется как транспорт, и поверх него выстроен дополнительный уровень абстракции (т.е. возможности HTTP, такие как номенклатура ошибок или заголовков, сознательно редуцируются до минимального уровня, а вся мета-информация переносится на уровень вышестоящего протокола).
К первой категории относятся API, которые принято обозначать словом «REST» или «RESTful». а ко второй — все виды RPC, а также прикладные протоколы типа SSH.
К первой категории относятся API, которые принято обозначать словом «REST» или «RESTful», а ко второй — все виды RPC, а также прикладные протоколы типа SSH.
**Во-вторых**, реализации HTTP API опираются на разные форматы передаваемых данных:
* REST API и некоторые RPC ([JSON-RPC](https://www.jsonrpc.org/), [GraphQL](https://graphql.org/)) полагаются в основном на формат [JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) (опционально дополненный передачей бинарных файлов);

View File

@ -315,7 +315,7 @@ POST /v1/users
Одна из самых больших проблем с точки зрения производительности, с которой сталкивается почти любой разработчик API, и внутренних, и публичных — это отказ в обслуживании вследствие лавины перезапросов: временные проблемы на бэкенде API (например, повышение времени ответа) могут привести к полной неработоспособности сервера, если клиенты начнут очень быстро повторять запрос, не получив или не дождавшись ответа, сгенерировав, таким образом, кратно большую нагрузку в короткий срок.
Лучшая практика в такой ситуации — это требовать, чтобы клиенты перезапрашивали эндпойнты API с увеличивающимся интервалом (скажем, перевый перезапрос происходит через одну секунду, второй — через две, третий через четыре, и так далее, но не больше одной минуты). Конечно, в случае публичного API такое требование никто не обязан соблюдать, но и хуже от его наличия вам точно не станет: хотя бы часть партнёров прочитает документацию и последует вашим рекомендациям.
Лучшая практика в такой ситуации — это требовать, чтобы клиенты перезапрашивали эндпойнты API с увеличивающимся интервалом (скажем, первый перезапрос происходит через одну секунду, второй — через две, третий через четыре, и так далее, но не больше одной минуты). Конечно, в случае публичного API такое требование никто не обязан соблюдать, но и хуже от его наличия вам точно не станет: хотя бы часть партнёров прочитает документацию и последует вашим рекомендациям.
Кроме того, вы можете разработать референсную реализацию политики перезапросов в ваших публичных SDK и следить за правильностью имплементации open-source модулей к вашему API.

View File

@ -1,6 +1,6 @@
### О паттернах проектирования в контексте API
Концепция [«паттернов»](https://en.wikipedia.org/wiki/Software_design_pattern#History) в области разработки программного обеспечения была введёна Кентом Бэком и Уордом Каннингемом в 1987 году, и популяризирован «бандой четырёх» (Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес) в их книге «Приёмы объектно-ориентированного проектирования. Паттерны проектирования», изданной в 1994 году. Согласно общепринятому определению, паттерны программирования — «повторяемая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста».
Концепция [«паттернов»](https://en.wikipedia.org/wiki/Software_design_pattern#History) в области разработки программного обеспечения была введена Кентом Бэком и Уордом Каннингемом в 1987 году, и популяризирован «бандой четырёх» (Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес) в их книге «Приёмы объектно-ориентированного проектирования. Паттерны проектирования», изданной в 1994 году. Согласно общепринятому определению, паттерны программирования — «повторяемая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста».
Если мы говорим об API, особенно если конечным потребителем этих API является разработчик (интерфейсы фреймворков, операционных систем), классические паттерны проектирования вполне к ним применимы. И действительно, многие из описанных в предыдущем разделе примеров представляют собой применение того или иного паттерна.

View File

@ -59,7 +59,7 @@ const pendingOrders = await api.
* нативное же обеспечение устойчивости к временному всплеску нагрузки на сервис — новые задачи встают в очередь (возможно, приоритизированную), фактически имплементируя [«маркерное ведро»](https://en.wikipedia.org/wiki/Token_bucket);
* организация взаимодействия в тех случаях, когда время исполнения операции превышает разумные значения (в случае сетевых API — типичное время срабатывания сетевых таймаутов, т.е. десятки секунд) либо является непредсказуемым.
Кроме того, асихнронное взаимодействие удобнее с точки зрения развития API в будущем: устройство системы, обрабатывающей такие запросы, может меняться в сторону усложнения и удлинения конвейера исполнения задачи, в то время как синхронным функциям придётся укладываться в разумные временные рамки, чтобы оставаться синхронными — что, конечно, ограничивает возможности рефакторинга внутренних механик.
Кроме того, асинхронное взаимодействие удобнее с точки зрения развития API в будущем: устройство системы, обрабатывающей такие запросы, может меняться в сторону усложнения и удлинения конвейера исполнения задачи, в то время как синхронным функциям придётся укладываться в разумные временные рамки, чтобы оставаться синхронными — что, конечно, ограничивает возможности рефакторинга внутренних механик.
**NB**: иногда можно встретить решение, при котором эндпойнт имеет двойной интерфейс и может вернуть как результат, так и ссылку на исполнение задания. Хотя для вас как разработчика API он может выглядеть логично (смогли «быстро» выполнить запрос, например, получить результат из кэша — вернули ответ; не смогли — вернули ссылку на задание), для пользователей API это решение крайне неудобно, поскольку заставляет поддерживать две ветки кода одновременно. Также встречается парадигма предоставления на выбор разработчику два набора эндпойнтов, синхронный и асинхронный, но по факту это просто перекладывание ответственности на партнёра.

View File

@ -80,7 +80,7 @@ GET /v1/orders/pending
**NB**: третий (и отчасти второй) варианты естественным образом приводят нас к схеме, характерной для клиентских устройств: push-уведомление само по себе не почти содержит полезной информации и только является сигналом для внеочередного поллинга.
Применение техник с отправкой только ограниченного набора данных помимо усложнения схемы взаимодействия и увеличения количества запросов имеет ещё один важный недостаток. Если в варианте 1 (сообщение содержит в себе все релевантные данные) мы можем рассчитывать на то, что возврат кода успеха подписчиком эквивалентен успешной обработке сообщения партнёром (что, вообще говоря, тоже не гарантировано, т.к. партнёр может использовать асинхронные схемы), то для вариантов 2 и 3 это заведомо не так: для обработки сообщений партнёр должен выполнить дополнительные действия, начиная с получения нужных данных о заказе. В этом случае нам необходимо иметь раздельные статусы — сообщение доставлено и сообщение обработано; в идеале, второе должно вытекать из логики работы API, т.е. сигналом о том, что сообщение обработано, является какое-то действие, совершаемое партнёром. В нашем кофейном примере это может быть перевод заказа партнёром из статуса `"new"` (заказ создан пользователем) в статус `"accepted"` или `"rejected"` (кофейня партнёра приняла или отклонила заказ). Тогда полный цикл обработки уведосления будет выглядеть так:
Применение техник с отправкой только ограниченного набора данных помимо усложнения схемы взаимодействия и увеличения количества запросов имеет ещё один важный недостаток. Если в варианте 1 (сообщение содержит в себе все релевантные данные) мы можем рассчитывать на то, что возврат кода успеха подписчиком эквивалентен успешной обработке сообщения партнёром (что, вообще говоря, тоже не гарантировано, т.к. партнёр может использовать асинхронные схемы), то для вариантов 2 и 3 это заведомо не так: для обработки сообщений партнёр должен выполнить дополнительные действия, начиная с получения нужных данных о заказе. В этом случае нам необходимо иметь раздельные статусы — сообщение доставлено и сообщение обработано; в идеале, второе должно вытекать из логики работы API, т.е. сигналом о том, что сообщение обработано, является какое-то действие, совершаемое партнёром. В нашем кофейном примере это может быть перевод заказа партнёром из статуса `"new"` (заказ создан пользователем) в статус `"accepted"` или `"rejected"` (кофейня партнёра приняла или отклонила заказ). Тогда полный цикл обработки уведомления будет выглядеть так:
```
// Уведомляем партнёра о том,

View File

@ -125,7 +125,7 @@ GET /v1/orders/{id}/events/history
Предположим, что у разработчика (вероятно, бизнес-партнёра вашей компании) написан какой-то код, выполняющий какую-то полезную бизнес функцию поверх этих событий — например, строит аналитику по затратам и доходам. Вполне логично ожидать, что этот код будет оперировать какой-то машиной состояний, которая будет переходить в то или иное состояние в зависимости от получения или неполучения события. Аналитический код наверняка сломается вследствие изменения порядка событий. В лучшем случае разработчик увидит какие-то исключения и будет вынужден разбираться с причиной; в худшем случае партнёр будет оперировать неправильной статистикой неопределённое время, пока не найдёт в ней ошибку.
Правильным решением было бы во-первых, изначально задокументировать порядок событий и допустимые состояния; во-вторых, продолжать генерировать событие `"payment_approved"` перед `"preparing_started"` (если вы приняли решение исполнять такой заказ — значит, по сути, подтвердили платёж) и добавить расширенную информацию о платеже.
Правильным решением было бы, во-первых, изначально задокументировать порядок событий и допустимые состояния; во-вторых, продолжать генерировать событие `"payment_approved"` перед `"preparing_started"` (если вы приняли решение исполнять такой заказ — значит, по сути, подтвердили платёж) и добавить расширенную информацию о платеже.
Этот пример подводит нас к ещё к одному правилу.

View File

@ -95,7 +95,7 @@ PUT /formatters/volume/ru/US
}
```
Таким образом, реалиазция вышеупомянутой функции `l10n.volume.format` сможет извлечь правила для локали `ru/US` и отформатировать представление объёма согласно им.
Таким образом, реализация вышеупомянутой функции `l10n.volume.format` сможет извлечь правила для локали `ru/US` и отформатировать представление объёма согласно им.
**NB**: мы, разумеется, в курсе, что таким простым форматом локализации единиц измерения в реальной жизни обойтись невозможно, и необходимо либо положиться на существующие библиотеки, либо разработать сложный формат описания (учитывающий, например, падежи слов и необходимую точность округления), либо принимать правила форматирования в императивном виде (т.е. в виде кода функции). Пример выше приведён исключительно в учебных целях.

View File

@ -45,7 +45,7 @@
* внутренние потребители, как правило, используют вполне конкретный технический стек, и API плохо оптимизирован под любые другие языки программирования / операционные системы / фреймворки;
* внутренние потребители гораздо лучше погружены в контекст, могут посмотреть исходный код или пообщаться напрямую с разработчиком API, и для них порог входа в технологию находится на совершенно другом уровне по сравнению с внешними потребителями;
* документация покрывает какой-то наиболее востребованный внутренними потребителями срез сценариев;
* линейка сервисов API, о которой мы расскажем ниже, зачастую попросту отсутствует, т.к. внутренними потребителям она не нужна.
* линейка сервисов API, о которой мы расскажем ниже, зачастую попросту отсутствует, т.к. внутренним потребителям она не нужна.
* Любые ресурсы выделяются в первую очередь на поддержку внутренних потребителей. Это означает, что:
* планы развития API для партнёров совершенно непрозрачны и бывает что попросту абсурдны; очевидные недоработки не исправляются годами;
* техническая поддержка внешних пользователей осуществляется по остаточному принципу.
@ -73,7 +73,7 @@
##### Терраформирование
Наконец, наиболее альтруистический подход к разработке API — предоставление его либо полностью бесплатно либо в формате открытого кода и открытых данных просто с целью изменения ландшафта: если сегодня за API никто не готов платить, то можно вложиться в популяризацию и продвижение функциональности, рассчитывая найти коммерческие ниши (в любом из перечисленных форматов) в будущем или повысить значимость и полезность API в глазах конечных пользователей (а значит и готовность потребителей платить за использование API). [В случае нашего кофейного примера — если компания-производитель умных кофе-машин предоставляет API полностью бесплатно в расчёте на то, что со временем наличие у кофе-машин API станет нормой, и появится возможность разработать новые монетизируемые сервисы за счёт этого.]
Наконец, наиболее альтруистический подход к разработке API — предоставление его либо полностью бесплатно, либо в формате открытого кода и открытых данных просто с целью изменения ландшафта: если сегодня за API никто не готов платить, то можно вложиться в популяризацию и продвижение функциональности, рассчитывая найти коммерческие ниши (в любом из перечисленных форматов) в будущем или повысить значимость и полезность API в глазах конечных пользователей (а значит и готовность потребителей платить за использование API). [В случае нашего кофейного примера — если компания-производитель умных кофе-машин предоставляет API полностью бесплатно в расчёте на то, что со временем наличие у кофе-машин API станет нормой, и появится возможность разработать новые монетизируемые сервисы за счёт этого.]
##### Серая зона

View File

@ -57,5 +57,5 @@
* Абсолютное большинство нагрузки на вашу техническую поддержку будет создавать первая категория: начинающим разработчикам гораздо сложнее найти ответы на свои вопросы или разобраться в проблеме самостоятельно, и они будут задавать их вам.
* При этом вторая категория потребителей будет гораздо более требовательна к качеству как продукта, так и поддержки, и при этом удовлетворить их запросы будет крайне нетривиально.
Наконец, практически невозможно в рамках одного продукта создать такой API, который одинаково хорошо подходит и начинающим разработчикам, и профессионалам; первым необходима максимальная простота реализации базовых сценариев использования API, вторым — возможность адаптировать использование API под конкретный стек технологий и парадигму разработки, и стоящие перед ними задачи, как правило, требуют глубокой кастомизации. Мы обсудим этот вопрос более подробно в главе [«Линейка сервисов API»](#api-product-range).
Наконец, практически невозможно в рамках одного продукта создать такой API, который одинаково хорошо подходит и начинающим разработчикам, и профессионалам; первым необходима максимальная простота реализации базовых сценариев использования API, вторым — возможность адаптировать использование API под конкретный стек технологий и парадигму разработки, и стоящие перед ними задачи, как правило, требуют глубокой кастомизации. Мы обсудим этот вопрос более подробно в главе [«Линейка сервисов API»](#api-product-range).

View File

@ -17,7 +17,7 @@
#### Вертикальное разделение сервисов API
Часто, однако, имеет смысл предоставлять несколько сервисов API, оперирующих одной и той же функциональностью. Напомним, что все разработчики делятся на две категории — профессионалов, которые ищут возможности глубокой кастомизации (поскольку работают в крупных ИТ-компаниях со сложившимся подходом к разработке), и начинающих разработчиков, которым необходим максимально заниженный порог входа. Максимально полно покрыть нужды обеих групп можно только разработав множество продуктов с разным порогом входа и требовательностью к профессиональному уровню программиста. Можно выделить следующие подвиды API, по убыванию требуемого уровня разработчиков.
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. главу [«Разделение уровней абстракции»](#api-design-separating-abstractions) и главу [«Слабая связность»](#back-compat-weak-coupling).]
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. главу [«Разделение уровней абстракции»](#api-design-separating-abstractions) и главу [«Слабая связность»](#back-compat-weak-coupling).]
2. Базовый уровень — работы с продуктовыми сущностями через формальные интерфейсы. [В случае нашего учебного API этому уровню соответствует HTTP API заказа.]
3. Упростить работу с продуктовыми сущностями можно, предоставив SDK для различных платформ, скрывающие под собой сложности работы с формальными интерфейсами и адаптирующие концепции API под соответствующие парадигмы (что позволяет разработчикам, знакомым только с конкретной платформой, не тратить время и не разбираться в формальных интерфейсах и протоколах).
4. Ещё более упростить работу можно с помощью сервисов, генерирующих код. В таком интерфейсе разработчик выбирает один из представленных шаблонов интеграции, кастомизирует некоторые параметры, и получает на выходе готовый фрагмент кода, который он может вставить в своё приложение (и, возможно, дописать необходимую функциональность с использованием API 1-3 уровней). Подобного рода подход ещё часто называют «программированием мышкой». [В случае нашего кофейного API примером такого сервиса мог бы служить визуальный редактор форм/экранов, в котором пользователь расставляет UI элементы, и в конечном итоге получает полный код приложения.]

View File

@ -37,7 +37,7 @@
Другая опасность заключается в том, что ключ могут банально украсть у добросовестного партнёра; в случае клиентских и веб-приложений это довольно тривиально.
Может показаться, что в случае предоставления серверных API проблема воровства ключей неактуальна, но, на самом деле, это не так. Предположим, что партнёр предоставляет свой собственный публичный сервис, который «под капотом» использует ваше API. Это часто означает, что в сервисе партнёра есть эндпойнт, предназначенный для конечных пользователей, который внутри делает запрос к API и возвращает результат, и этот эндпойнт может использоваться злоумышленником как эквивалент API. Конечно, можно объявить такой фрод проблемой партнёра, однако было бы, во-первых, наивно ожидать от каждого партнёра реализации собственной антифрод-системы, которая позволит выявлять таких недобросовестных пользователей, и, во-вторых, это попросту неэффективно: очевидно, что централизованная система борьбы с фродерами всегда будет более эффективной, нежели множество частных любительских реализаций. К томе же, и серверные ключи могут быть украдены: это сложее, чем украсть клиентские, но не невозможно. Популярный API рано или поздно столкнётся с тем, что украденные ключи будут выложены в свободный доступ (или владелец ключа просто будет делиться им со знакомыми по доброте душевной).
Может показаться, что в случае предоставления серверных API проблема воровства ключей неактуальна, но, на самом деле, это не так. Предположим, что партнёр предоставляет свой собственный публичный сервис, который «под капотом» использует ваше API. Это часто означает, что в сервисе партнёра есть эндпойнт, предназначенный для конечных пользователей, который внутри делает запрос к API и возвращает результат, и этот эндпойнт может использоваться злоумышленником как эквивалент API. Конечно, можно объявить такой фрод проблемой партнёра, однако было бы, во-первых, наивно ожидать от каждого партнёра реализации собственной антифрод-системы, которая позволит выявлять таких недобросовестных пользователей, и, во-вторых, это попросту неэффективно: очевидно, что централизованная система борьбы с фродерами всегда будет более эффективной, нежели множество частных любительских реализаций. К томе же, и серверные ключи могут быть украдены: это сложнее, чем украсть клиентские, но не невозможно. Популярный API рано или поздно столкнётся с тем, что украденные ключи будут выложены в свободный доступ (или владелец ключа просто будет делиться им со знакомыми по доброте душевной).
Так или иначе, встаёт вопрос независимой валидации: каким образом можно проконтролировать, действительно ли API используется потребителем в соответствии с пользовательским соглашением.

View File

@ -23,7 +23,7 @@
В случае сервисов для конечных пользователей основным методом дополнительной аутентификации является перенаправление на страницу с капчей. В случае API это может быть весьма проблематично, особенно если вы пренебрегли советом [«Предусмотрите ограничения»](#chapter-11-paragraph-19) — во многих случаях вам придётся переложить имплементацию этого сценария на партнёра (т.е. это партнёр должен будет показывать капчу и идентифицировать пользователя, основываясь на сигналах, поступающих от эндпойнтов API) что, конечно, сильно снижает комфортность работы с таким API.
**NB**. Вместо капчи здесь могут быть любые другие действия, вводящие дополнительные факторы аутентификации. Это может быть, например, подтверждение номера телефона или второй шаг протокола 3D-Secure. Важно здесь то, что запрос второго шага аутентификации должен быть предусмотрен в API, поскольку добавить его его обратно совместимым образом к существующим endpoint-ам нельзя.
**NB**. Вместо капчи здесь могут быть любые другие действия, вводящие дополнительные факторы аутентификации. Это может быть, например, подтверждение номера телефона или второй шаг протокола 3D-Secure. Важно здесь то, что запрос второго шага аутентификации должен быть предусмотрен в API, поскольку добавить его обратно совместимым образом к существующим endpoint-ам нельзя.
Другие популярные способы распознать робота — предложить ему приманку (honeypot) или использовать методы проверки среды исполнения (начиная от достаточно простых вроде исполнения JavaScript на странице и заканчивая технологиями проверки целостности приложения).

View File

@ -24,7 +24,7 @@
2. Обратный сценарий — когда техподдержка предоставляется только на платной основе, и на вопросы отвечают непосредственно разработчики; пусть на качество и релевантность запросов такая модель не оказывает большого влияния (вашим API продолжают пользоваться, в основном, новички; вы лишь отсекаете тех из них, у кого нет денег на платную поддержку), но, по крайней мере, вы не будете испытывать проблем с наймом, поскольку сможете позволить себе роскошь поставить технического специалиста на первую линию поддержки.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. главу [«Взаимодействие с разработчиками»]()). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. главу [«Взаимодействие с разработчиками»]()). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
Важный момент заключается в том, что, какой вариант оказания техподдержки вы ни выберете, финально на вопросы пользователей придётся отвечать разработчикам API просто в силу того факта, что полноценно разобраться в коде партнёра может только программист. Из этого следует два важных вывода.

View File

@ -32,7 +32,7 @@
Исходя из вышесказанного, примеры кода — самый важный инструмент привлечения и поддержки новых пользователей вашего API. Исключительно важно подобрать примеры так, чтобы они облегчали новичкам работу с API; неправильно выстроенные примеры только ухудшат качество вашей документации. При составлении примеров следует руководствоваться следующими принципами:
* примеры должны покрывать актуальные сценарии использования API: чем лучше вы угадаете наиболее частые запросы разработчиков, тем более дружелюбным и простым для входа будет выглядеть ваш API в их глазах;
* примеры должны быть лаконичными и атомарными: cмешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;
* примеры должны быть лаконичными и атомарными: смешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;
* код примеров должен быть максимально приближен к реальному приложению; автор этой книги сталкивался с ситуацией, когда синтетический фрагмент кода, абсолютно бессмысленный в реальном мире, был бездумно растиражирован разработчиками в огромном количестве.
В идеале примеры должны быть провязаны со всеми остальными видами документации. В частности, референс должен содержать примеры, релевантные описанию сущностей.

View File

@ -6,7 +6,7 @@
Конечно, в идеальном случае однажды выпущенный API должен жить вечно; но, как разумные люди, мы понимаем, что в реальной жизни это невозможно. Даже если мы продолжаем поддерживать старые версии, они все равно морально устаревают: партнёры должны потратить ресурсы на переписывание кода под новые версии API, если хотят получить доступ к новой функциональности.
Автор этой книги формулирует для себя золотое правило выпуска новых версий API так: период времени, после которого партнеру потребуется переписать свой код, должен совпадать с жизненным циклом приложений в вашей предметной области (см. главу [«Постановка проблемы обратной совместимости»](#back-compat-statement)). Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline), даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
Автор этой книги формулирует для себя золотое правило выпуска новых версий API так: период времени, после которого партнеру потребуется переписать свой код, должен совпадать с жизненным циклом приложений в вашей предметной области (см. главу [«Постановка проблемы обратной совместимости»](#back-compat-statement)). Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline), даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
В этом аспекте интеграция с крупными компаниями, имеющими собственный отдел разработки, существенно отличается от взаимодействия с одиночными разработчиками-любителями: первые, с одной стороны, с гораздо большей вероятностью найдут в вашем API недокументированные возможности и неисправленные ошибки; с другой стороны, в силу большей бюрократичности внутренних процессов, исправление проблем может затянуться на месяцы, а то и годы. Общая рекомендация здесь — поддерживать возможность подключения старых минорных версий API достаточно долго для того, чтобы самый забюрократизированный партнёр успел переключиться на новую версию.

View File

@ -1,6 +1,6 @@
### О концепции HTTP API и терминологии
Вопросы организации HTTP API — к большому сожалению, одни из самых «холиварных». Будучи одной из самых популярных и притом весьма непростых в понимании технологий (в виду большого по объёму и фрагментированного на отдельные RFC стандарта), спецификация HTTP обречена быть плохо понятой и превратно истолкованной миллионами разработчиков и многими тысячами учебных пособий. Поэтому, прежде чем переходить непосредственно к полезной части настоящего раздела, мы обязаны дать уточнения, о чём же всё-таки пойдёт речь.
Вопросы организации HTTP API — к большому сожалению, одни из самых «холиварных». Будучи одной из самых популярных и притом весьма непростых в понимании технологий (ввиду большого по объёму и фрагментированного на отдельные RFC стандарта), спецификация HTTP обречена быть плохо понятой и превратно истолкованной миллионами разработчиков и многими тысячами учебных пособий. Поэтому, прежде чем переходить непосредственно к полезной части настоящего раздела, мы обязаны дать уточнения, о чём же всё-таки пойдёт речь.
Так сложилось, что в настоящий момент сетевой стек, используемый для разработки распределённых API, практически полностью унифицирован в двух точках. Одна из них — это Internet protocol suite, состоящий из базового протокола IP и надстройки в виде TCP или UDP над ним. На сегодняшний день альтернативы TCP/IP используются в чрезвычайно ограниченном спектре задач, и средний разработчик практически не сталкивается ни с каким другим сетевым стеком. Однако у TCP/IP с прикладной точки зрения есть существенный недостаток — он оперирует поверх системы IP-адресов, которые плохо подходят для организации распределённых систем:
* во-первых, люди не запоминают IP-адреса и предпочитают оперировать «говорящими» именами;

View File

@ -112,7 +112,7 @@ X-OurApi-Error-Kind: wrong_parameter_value
#### Серверные ошибки
**Ошибки `5xx`** индицируют, что клиент, со своей стороны, выполнил запрос правильно, и проблема заключается в сервере. Для клиента, по большому счёту, важно только то, имеет ли смысл повторять запрос и, если да, то через какое время. Если учесть, что в любых публично доступных API причиных серверных ошибок, как правило, не раскрывают — в абсолютном большинстве кодов `500 Internal Server Error` и `503 Service Unavailable` достаточно для индикации серверных ошибок (второй код указывает, что отказ в обслуживании имеет разовый характер и есть смысл автоматически повторить запрос), или можно вовсе ограничиться одним из них с опциональным заголовком `Retry-After`.
**Ошибки `5xx`** индицируют, что клиент, со своей стороны, выполнил запрос правильно, и проблема заключается в сервере. Для клиента, по большому счёту, важно только то, имеет ли смысл повторять запрос и, если да, то через какое время. Если учесть, что в любых публично доступных API причины серверных ошибок, как правило, не раскрывают — в абсолютном большинстве кодов `500 Internal Server Error` и `503 Service Unavailable` достаточно для индикации серверных ошибок (второй код указывает, что отказ в обслуживании имеет разовый характер и есть смысл автоматически повторить запрос), или можно вовсе ограничиться одним из них с опциональным заголовком `Retry-After`.
Разумеется, серверные ошибки также должны содержать информацию для разработчика и для конечного пользователя системы с описанием действий, которые необходимо выполнить при получении ошибки, и вот здесь мы вступаем на очень скользкую территорию.

View File

@ -207,6 +207,6 @@
Как мы видим, простая операция «попробовать продлить предложение» выливается в громоздкий код, в котором легко ошибиться, и, что ещё важнее, который совершенно не нужен разработчику приложения. Было бы гораздо проще, если бы этой ошибки *вовсе не было в SDK*, т.е. попытки обновления и перезапросы выполнялись бы автоматически.
Аналогичные ситуации возникают и в случае нестрого-консистентных API или оптимистичного управления параллелизмом — и вообще в любом API, в котором фон ошибок является ожидаемым (что в в случае распределённых клиент-серверных API является нормой жизни). Передача версии ресурса и/или последних известных идентификаторов в эндпойнты с политикой read-your-writes — техническая необходимость, вызванная стремлением вендора API удешевить эксплуатацию и увеличить пропускную способность. Для разработчика приложения написание кода, имплементирующего эти политики — попросту напрасная трата времени.
Аналогичные ситуации возникают и в случае нестрого-консистентных API или оптимистичного управления параллелизмом — и вообще в любом API, в котором фон ошибок является ожидаемым (что в случае распределённых клиент-серверных API является нормой жизни). Передача версии ресурса и/или последних известных идентификаторов в эндпойнты с политикой read-your-writes — техническая необходимость, вызванная стремлением вендора API удешевить эксплуатацию и увеличить пропускную способность. Для разработчика приложения написание кода, имплементирующего эти политики — попросту напрасная трата времени.
5. Хранение данных в постоянной памяти (таких, как токены авторизации, ключи идемпотентности при перезапросах, идентификаторы черновиков при двухфазных коммитах и т.д.) также является ответственностью клиента и с трудом поддаётся формализации при кодогенерации.

View File

@ -103,7 +103,7 @@ try {
**NB**: вторым параметром в `acquireLock` мы передали время жизни блокировки — 2 секунды. Если в течение двух секунд блокировка не снята, она будет отменена автоматически.
В таком подходе мы можем реализовать не только блокировки, но и программируемые прерывания и реакцию на на них:
В таком подходе мы можем реализовать не только блокировки, но и программируемые прерывания и реакцию на них:
```
const lock = await searchBox

View File

@ -2,7 +2,7 @@
Прежде чем излагать рекомендации, нам следует определиться с тем, что мы считаем «хорошим» API, и какую пользу мы получаем от того, что наш API «хороший».
Начнём со второго вопроса. Очевидно, «хорошесть» API определяется в первую очередь тем, насколько он помогает разработчикам решать стоящие перед ними задачи. (Можно резонно возразить, что решение задач, стоящих перед разработчиками, не обязательно влечёт за собой выполнение целей, которые мы ставим перед собой, предлагая разработчикам API. Однако манипуляция общественным мнением не входит в область интересов автора этой книги: здесь и далее предполагается, что API существует в первую очередь для того, чтобы разработчики решали с его помощью свои задачи, а не ради каких-то завуалированных целей).
Начнём со второго вопроса. Очевидно, «хорошесть» API определяется в первую очередь тем, насколько он помогает разработчикам решать стоящие перед ними задачи. (Можно резонно возразить, что решение задач, стоящих перед разработчиками, необязательно влечёт за собой выполнение целей, которые мы ставим перед собой, предлагая разработчикам API. Однако манипуляция общественным мнением не входит в область интересов автора этой книги: здесь и далее предполагается, что API существует в первую очередь для того, чтобы разработчики решали с его помощью свои задачи, а не ради каких-то завуалированных целей).
Как же дизайн API может помочь разработчику? Очень просто: API должен решать задачи *максимально удобно и понятно*. Путь разработчика от формулирования своей задачи до написания работающего кода должен быть максимально коротким. Это, в том числе, означает, что:

View File

@ -93,7 +93,7 @@
Для минорных версий возможны два варианта:
* если вы предоставляете только серверный API и компилируемые SDK, вы можете в принципе не поддерживать никакие минорные версии API, помимо актуальной (см. нижк); однако, на определённом этапе развития популярных API становится хорошим тоном поддерживать по крайней мере две последние версии;
* если вы предоставляете только серверный API и компилируемые SDK, вы можете в принципе не поддерживать никакие минорные версии API, помимо актуальной (см. ниже); однако, на определённом этапе развития популярных API становится хорошим тоном поддерживать по крайней мере две последние версии;
* если вы предоставляете code-on-demand SDK, то вот здесь хорошим тоном является поддержка предыдущих минорных версий SDK в работающем состоянии на срок, достаточный для того, чтобы разработчики могли протестировать своё приложение с новой версией и внести какие-то правки по необходимости. Так как полностью переписывать приложения при этом не надо, разумно ориентироваться на длину релизных циклов в вашей индустрии, обычно это несколько месяцев в худшем случае.
#### Одновременный доступ к нескольким минорным версиям API

View File

@ -125,7 +125,7 @@ GET /v1/orders/{id}/events/history
Предположим, что у разработчика (вероятно, бизнес-партнёра вашей компании) написан какой-то код, выполняющий какую-то полезную бизнес функцию поверх этих событий — например, строит аналитику по затратам и доходам. Вполне логично ожидать, что этот код будет оперировать какой-то машиной состояний, которая будет переходить в то или иное состояние в зависимости от получения или неполучения события. Аналитический код наверняка сломается вследствие изменения порядка событий. В лучшем случае разработчик увидит какие-то исключения и будет вынужден разбираться с причиной; в худшем случае партнёр будет оперировать неправильной статистикой неопределённое время, пока не найдёт в ней ошибку.
Правильным решением было бы во-первых, изначально задокументировать порядок событий и допустимые состояния; во-вторых, продолжать генерировать событие `"payment_approved"` перед `"preparing_started"` (если вы приняли решение исполнять такой заказ — значит, по сути, подтвердили платёж) и добавить расширенную информацию о платеже.
Правильным решением было бы, во-первых, изначально задокументировать порядок событий и допустимые состояния; во-вторых, продолжать генерировать событие `"payment_approved"` перед `"preparing_started"` (если вы приняли решение исполнять такой заказ — значит, по сути, подтвердили платёж) и добавить расширенную информацию о платеже.
Этот пример подводит нас к ещё к одному правилу.

View File

@ -95,7 +95,7 @@ PUT /formatters/volume/ru/US
}
```
Таким образом, реалиазция вышеупомянутой функции `l10n.volume.format` сможет извлечь правила для локали `ru/US` и отформатировать представление объёма согласно им.
Таким образом, реализация вышеупомянутой функции `l10n.volume.format` сможет извлечь правила для локали `ru/US` и отформатировать представление объёма согласно им.
**NB**: мы, разумеется, в курсе, что таким простым форматом локализации единиц измерения в реальной жизни обойтись невозможно, и необходимо либо положиться на существующие библиотеки, либо разработать сложный формат описания (учитывающий, например, падежи слов и необходимую точность округления), либо принимать правила форматирования в императивном виде (т.е. в виде кода функции). Пример выше приведён исключительно в учебных целях.

View File

@ -45,7 +45,7 @@
* внутренние потребители, как правило, используют вполне конкретный технический стек, и API плохо оптимизирован под любые другие языки программирования / операционные системы / фреймворки;
* внутренние потребители гораздо лучше погружены в контекст, могут посмотреть исходный код или пообщаться напрямую с разработчиком API, и для них порог входа в технологию находится на совершенно другом уровне по сравнению с внешними потребителями;
* документация покрывает какой-то наиболее востребованный внутренними потребителями срез сценариев;
* линейка сервисов API, о которой мы расскажем ниже, зачастую попросту отсутствует, т.к. внутренними потребителям она не нужна.
* линейка сервисов API, о которой мы расскажем ниже, зачастую попросту отсутствует, т.к. внутренним потребителям она не нужна.
* Любые ресурсы выделяются в первую очередь на поддержку внутренних потребителей. Это означает, что:
* планы развития API для партнёров совершенно непрозрачны и бывает что попросту абсурдны; очевидные недоработки не исправляются годами;
* техническая поддержка внешних пользователей осуществляется по остаточному принципу.

View File

@ -10,7 +10,7 @@
* в частности, разработчики скептически относятся к громким рекламным заявлениям и готовы разбираться в том, насколько эти заявления соответствуют истине;
* к разработчикам крайне сложно обращаться через стандартные маркетинговые каналы; помимо того, что они получают информацию в основном из ускоспециализированных сообществ, программисты также смотрят в первую очередь на мнения, подтверждённые конкретными цифрами и примерами (желательно — примерами кода);
* к разработчикам крайне сложно обращаться через стандартные маркетинговые каналы; помимо того, что они получают информацию в основном из узкоспециализированных сообществ, программисты также смотрят в первую очередь на мнения, подтверждённые конкретными цифрами и примерами (желательно — примерами кода);
* мнения «инфлюэнсеров» в такой среде значат очень мало, поскольку ничьё мнение не принимается на веру;
@ -57,5 +57,5 @@
* Абсолютное большинство нагрузки на вашу техническую поддержку будет создавать первая категория: начинающим разработчикам гораздо сложнее найти ответы на свои вопросы или разобраться в проблеме самостоятельно, и они будут задавать их вам.
* При этом вторая категория потребителей будет гораздо более требовательна к качеству как продукта, так и поддержки, и при этом удовлетворить их запросы будет крайне нетривиально.
Наконец, практически невозможно в рамках одного продукта создать такой API, который одинаково хорошо подходит и начинающим разработчикам, и профессионалам; первым необходима максимальная простота реализации базовых сценариев использования API, вторым — возможность адаптировать использование API под конкретный стек технологий и парадигму разработки, и стоящие перед ними задачи, как правило, требуют глубокой кастомизации. Мы обсудим этот вопрос более подробно в главе [«Линейка сервисов API»](#api-product-range).
Наконец, практически невозможно в рамках одного продукта создать такой API, который одинаково хорошо подходит и начинающим разработчикам, и профессионалам; первым необходима максимальная простота реализации базовых сценариев использования API, вторым — возможность адаптировать использование API под конкретный стек технологий и парадигму разработки, и стоящие перед ними задачи, как правило, требуют глубокой кастомизации. Мы обсудим этот вопрос более подробно в главе [«Линейка сервисов API»](#api-product-range).

View File

@ -17,7 +17,7 @@
#### Вертикальное разделение сервисов API
Часто, однако, имеет смысл предоставлять несколько сервисов API, оперирующих одной и той же функциональностью. Напомним, что все разработчики делятся на две категории — профессионалов, которые ищут возможности глубокой кастомизации (поскольку работают в крупных ИТ-компаниях со сложившимся подходом к разработке), и начинающих разработчиков, которым необходим максимально заниженный порог входа. Максимально полно покрыть нужды обеих групп можно только разработав множество продуктов с разным порогом входа и требовательностью к профессиональному уровню программиста. Можно выделить следующие подвиды API, по убыванию требуемого уровня разработчиков.
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. главу [«Разделение уровней абстракции»](#api-design-separating-abstractions) и главу [«Слабая связность»](#back-compat-weak-coupling).]
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. главу [«Разделение уровней абстракции»](#api-design-separating-abstractions) и главу [«Слабая связность»](#back-compat-weak-coupling).]
2. Базовый уровень — работы с продуктовыми сущностями через формальные интерфейсы. [В случае нашего учебного API этому уровню соответствует HTTP API заказа.]
3. Упростить работу с продуктовыми сущностями можно, предоставив SDK для различных платформ, скрывающие под собой сложности работы с формальными интерфейсами и адаптирующие концепции API под соответствующие парадигмы (что позволяет разработчикам, знакомым только с конкретной платформой, не тратить время и не разбираться в формальных интерфейсах и протоколах).
4. Ещё более упростить работу можно с помощью сервисов, генерирующих код. В таком интерфейсе разработчик выбирает один из представленных шаблонов интеграции, кастомизирует некоторые параметры, и получает на выходе готовый фрагмент кода, который он может вставить в своё приложение (и, возможно, дописать необходимую функциональность с использованием API 1-3 уровней). Подобного рода подход ещё часто называют «программированием мышкой». [В случае нашего кофейного API примером такого сервиса мог бы служить визуальный редактор форм/экранов, в котором пользователь расставляет UI элементы, и в конечном итоге получает полный код приложения.]

View File

@ -37,7 +37,7 @@
Другая опасность заключается в том, что ключ могут банально украсть у добросовестного партнёра; в случае клиентских и веб-приложений это довольно тривиально.
Может показаться, что в случае предоставления серверных API проблема воровства ключей неактуальна, но, на самом деле, это не так. Предположим, что партнёр предоставляет свой собственный публичный сервис, который «под капотом» использует ваше API. Это часто означает, что в сервисе партнёра есть эндпойнт, предназначенный для конечных пользователей, который внутри делает запрос к API и возвращает результат, и этот эндпойнт может использоваться злоумышленником как эквивалент API. Конечно, можно объявить такой фрод проблемой партнёра, однако было бы, во-первых, наивно ожидать от каждого партнёра реализации собственной антифрод-системы, которая позволит выявлять таких недобросовестных пользователей, и, во-вторых, это попросту неэффективно: очевидно, что централизованная система борьбы с фродерами всегда будет более эффективной, нежели множество частных любительских реализаций. К томе же, и серверные ключи могут быть украдены: это сложее, чем украсть клиентские, но не невозможно. Популярный API рано или поздно столкнётся с тем, что украденные ключи будут выложены в свободный доступ (или владелец ключа просто будет делиться им со знакомыми по доброте душевной).
Может показаться, что в случае предоставления серверных API проблема воровства ключей неактуальна, но, на самом деле, это не так. Предположим, что партнёр предоставляет свой собственный публичный сервис, который «под капотом» использует ваше API. Это часто означает, что в сервисе партнёра есть эндпойнт, предназначенный для конечных пользователей, который внутри делает запрос к API и возвращает результат, и этот эндпойнт может использоваться злоумышленником как эквивалент API. Конечно, можно объявить такой фрод проблемой партнёра, однако было бы, во-первых, наивно ожидать от каждого партнёра реализации собственной антифрод-системы, которая позволит выявлять таких недобросовестных пользователей, и, во-вторых, это попросту неэффективно: очевидно, что централизованная система борьбы с фродерами всегда будет более эффективной, нежели множество частных любительских реализаций. К томе же, и серверные ключи могут быть украдены: это сложнее, чем украсть клиентские, но не невозможно. Популярный API рано или поздно столкнётся с тем, что украденные ключи будут выложены в свободный доступ (или владелец ключа просто будет делиться им со знакомыми по доброте душевной).
Так или иначе, встаёт вопрос независимой валидации: каким образом можно проконтролировать, действительно ли API используется потребителем в соответствии с пользовательским соглашением.

View File

@ -23,7 +23,7 @@
В случае сервисов для конечных пользователей основным методом дополнительной аутентификации является перенаправление на страницу с капчей. В случае API это может быть весьма проблематично, особенно если вы пренебрегли советом [«Предусмотрите ограничения»](#chapter-11-paragraph-19) — во многих случаях вам придётся переложить имплементацию этого сценария на партнёра (т.е. это партнёр должен будет показывать капчу и идентифицировать пользователя, основываясь на сигналах, поступающих от эндпойнтов API) что, конечно, сильно снижает комфортность работы с таким API.
**NB**. Вместо капчи здесь могут быть любые другие действия, вводящие дополнительные факторы аутентификации. Это может быть, например, подтверждение номера телефона или второй шаг протокола 3D-Secure. Важно здесь то, что запрос второго шага аутентификации должен быть предусмотрен в API, поскольку добавить его его обратно совместимым образом к существующим endpoint-ам нельзя.
**NB**. Вместо капчи здесь могут быть любые другие действия, вводящие дополнительные факторы аутентификации. Это может быть, например, подтверждение номера телефона или второй шаг протокола 3D-Secure. Важно здесь то, что запрос второго шага аутентификации должен быть предусмотрен в API, поскольку добавить его обратно совместимым образом к существующим endpoint-ам нельзя.
Другие популярные способы распознать робота — предложить ему приманку (honeypot) или использовать методы проверки среды исполнения (начиная от достаточно простых вроде исполнения JavaScript на странице и заканчивая технологиями проверки целостности приложения).

View File

@ -24,7 +24,7 @@
2. Обратный сценарий — когда техподдержка предоставляется только на платной основе, и на вопросы отвечают непосредственно разработчики; пусть на качество и релевантность запросов такая модель не оказывает большого влияния (вашим API продолжают пользоваться, в основном, новички; вы лишь отсекаете тех из них, у кого нет денег на платную поддержку), но, по крайней мере, вы не будете испытывать проблем с наймом, поскольку сможете позволить себе роскошь поставить технического специалиста на первую линию поддержки.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. главу [«Взаимодействие с разработчиками»]()). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. главу [«Взаимодействие с разработчиками»]()). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
Важный момент заключается в том, что, какой вариант оказания техподдержки вы ни выберете, финально на вопросы пользователей придётся отвечать разработчикам API просто в силу того факта, что полноценно разобраться в коде партнёра может только программист. Из этого следует два важных вывода.

View File

@ -32,7 +32,7 @@
Исходя из вышесказанного, примеры кода — самый важный инструмент привлечения и поддержки новых пользователей вашего API. Исключительно важно подобрать примеры так, чтобы они облегчали новичкам работу с API; неправильно выстроенные примеры только ухудшат качество вашей документации. При составлении примеров следует руководствоваться следующими принципами:
* примеры должны покрывать актуальные сценарии использования API: чем лучше вы угадаете наиболее частые запросы разработчиков, тем более дружелюбным и простым для входа будет выглядеть ваш API в их глазах;
* примеры должны быть лаконичными и атомарными: cмешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;
* примеры должны быть лаконичными и атомарными: смешивание в одном фрагменте кода множества разных трюков из различных предметных областей резко снижает его понятность и применимость;
* код примеров должен быть максимально приближен к реальному приложению; автор этой книги сталкивался с ситуацией, когда синтетический фрагмент кода, абсолютно бессмысленный в реальном мире, был бездумно растиражирован разработчиками в огромном количестве.
В идеале примеры должны быть провязаны со всеми остальными видами документации. В частности, референс должен содержать примеры, релевантные описанию сущностей.

View File

@ -6,7 +6,7 @@
Конечно, в идеальном случае однажды выпущенный API должен жить вечно; но, как разумные люди, мы понимаем, что в реальной жизни это невозможно. Даже если мы продолжаем поддерживать старые версии, они все равно морально устаревают: партнёры должны потратить ресурсы на переписывание кода под новые версии API, если хотят получить доступ к новой функциональности.
Автор этой книги формулирует для себя золотое правило выпуска новых версий API так: период времени, после которого партнеру потребуется переписать свой код, должен совпадать с жизненным циклом приложений в вашей предметной области (см. главу [«Постановка проблемы обратной совместимости»](#back-compat-statement)). Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline), даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
Автор этой книги формулирует для себя золотое правило выпуска новых версий API так: период времени, после которого партнеру потребуется переписать свой код, должен совпадать с жизненным циклом приложений в вашей предметной области (см. главу [«Постановка проблемы обратной совместимости»](#back-compat-statement)). Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline), даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
В этом аспекте интеграция с крупными компаниями, имеющими собственный отдел разработки, существенно отличается от взаимодействия с одиночными разработчиками-любителями: первые, с одной стороны, с гораздо большей вероятностью найдут в вашем API недокументированные возможности и неисправленные ошибки; с другой стороны, в силу большей бюрократичности внутренних процессов, исправление проблем может затянуться на месяцы, а то и годы. Общая рекомендация здесь — поддерживать возможность подключения старых минорных версий API достаточно долго для того, чтобы самый забюрократизированный партнёр успел переключиться на новую версию.