You've already forked The-API-Book
mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-08-10 21:51:42 +02:00
stylistic fixes
This commit is contained in:
@@ -137,10 +137,10 @@ h4, h5 {
|
|||||||
<p>Более подробно о жизненном цикле API и политиках выпуска новых версий будет рассказано в разделе II.</p><div class="page-break"></div><h3 id="5">Глава 5. О версионировании</h3>
|
<p>Более подробно о жизненном цикле API и политиках выпуска новых версий будет рассказано в разделе II.</p><div class="page-break"></div><h3 id="5">Глава 5. О версионировании</h3>
|
||||||
<p>Здесь и далее мы будем придерживаться принципов версионирования <a href="https://semver.org/">semver</a>:</p>
|
<p>Здесь и далее мы будем придерживаться принципов версионирования <a href="https://semver.org/">semver</a>:</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Версия API задаётся тремя цифрами, вида <code>1.2.3</code></li>
|
<li>Версия API задаётся тремя цифрами, вида <code>1.2.3</code>.</li>
|
||||||
<li>Первая цифра (мажорная версия) увеличивается при обратно несовместимых изменениях в API</li>
|
<li>Первая цифра (мажорная версия) увеличивается при обратно несовместимых изменениях в API.</li>
|
||||||
<li>Вторая цифра (минорная версия) увеличивается при добавлении новой функциональности с сохранением обратной совместимости</li>
|
<li>Вторая цифра (минорная версия) увеличивается при добавлении новой функциональности с сохранением обратной совместимости.</li>
|
||||||
<li>Третья цифра (патч) увеличивается при выпуске новых версий, содержащих только исправление ошибок</li>
|
<li>Третья цифра (патч) увеличивается при выпуске новых версий, содержащих только исправление ошибок.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Выражения «мажорная версия API» и «версия API, содержащая обратно несовместимые изменения функциональности» тем самым следует считать эквивалентными.</p>
|
<p>Выражения «мажорная версия API» и «версия API, содержащая обратно несовместимые изменения функциональности» тем самым следует считать эквивалентными.</p>
|
||||||
<p>Более подробно о политиках версионирования будет рассказано в разделе II. В разделе I мы ограничимся лишь указанием версии API в формате <code>v1</code>, <code>v2</code>, etc.</p><div class="page-break"></div><h3 id="6">Глава 6. Условные обозначения и терминология</h3>
|
<p>Более подробно о политиках версионирования будет рассказано в разделе II. В разделе I мы ограничимся лишь указанием версии API в формате <code>v1</code>, <code>v2</code>, etc.</p><div class="page-break"></div><h3 id="6">Глава 6. Условные обозначения и терминология</h3>
|
||||||
@@ -168,10 +168,10 @@ Cache-Control: no-cache
|
|||||||
<p>Её следует читать так:</p>
|
<p>Её следует читать так:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>выполняется POST-запрос к ресурсу <code>/v1/bucket/{id}/some-resource</code>, где <code>{id}</code> заменяется на некоторый идентификатор <code>bucket</code>-а (при отсутствии уточнений подстановки вида <code>{something}</code> следует относить к ближайшему термину слева);</li>
|
<li>выполняется POST-запрос к ресурсу <code>/v1/bucket/{id}/some-resource</code>, где <code>{id}</code> заменяется на некоторый идентификатор <code>bucket</code>-а (при отсутствии уточнений подстановки вида <code>{something}</code> следует относить к ближайшему термину слева);</li>
|
||||||
<li>запрос сопровождается (помимо стандартных заголовков, которые мы опускаем) дополнительным заголовком X-Idempotency-Token;</li>
|
<li>запрос сопровождается (помимо стандартных заголовков, которые мы опускаем) дополнительным заголовком <code>X-Idempotency-Token</code>;</li>
|
||||||
<li>фразы в угловых скобках (<code><токен идемпотентности></code>) описывают семантику значения сущности (поля, заголовка, параметра);</li>
|
<li>фразы в угловых скобках (<code><токен идемпотентности></code>) описывают семантику значения сущности (поля, заголовка, параметра);</li>
|
||||||
<li>в качестве тела запроса передаётся JSON, содержащий поле <code>some_parameter</code> со значением <code>value</code> и ещё какие-то поля, которые для краткости опущены (что показано многоточием);</li>
|
<li>в качестве тела запроса передаётся JSON, содержащий поле <code>some_parameter</code> со значением <code>value</code> и ещё какие-то поля, которые для краткости опущены (что показано многоточием);</li>
|
||||||
<li>в ответ (индицируется стрелкой <code>→</code>) сервер возвращает статус 404 Not Found; статус может быть опущен (отсутствие статуса следует трактовать как <code>200 OK</code>);</li>
|
<li>в ответ (индицируется стрелкой <code>→</code>) сервер возвращает статус <code>404 Not Found</code>; статус может быть опущен (отсутствие статуса следует трактовать как <code>200 OK</code>);</li>
|
||||||
<li>в ответе также могут находиться дополнительные заголовки, на которые мы обращаем внимание;</li>
|
<li>в ответе также могут находиться дополнительные заголовки, на которые мы обращаем внимание;</li>
|
||||||
<li>телом ответа является JSON, состоящий из единственного поля <code>error_message</code>; отсутствие значения поля означает, что его значением является именно то, что в этом поле и ожидается — в данном случае какое-то сообщение об ошибке.</li>
|
<li>телом ответа является JSON, состоящий из единственного поля <code>error_message</code>; отсутствие значения поля означает, что его значением является именно то, что в этом поле и ожидается — в данном случае какое-то сообщение об ошибке.</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -196,7 +196,7 @@ Cache-Control: no-cache
|
|||||||
<li><p>Какую проблему <em>мы</em> решаем? Действительно ли решение этой проблемы находится в нашей компетенции? Действительно ли мы находимся в той позиции, чтобы решить эту проблему?</p></li>
|
<li><p>Какую проблему <em>мы</em> решаем? Действительно ли решение этой проблемы находится в нашей компетенции? Действительно ли мы находимся в той позиции, чтобы решить эту проблему?</p></li>
|
||||||
<li><p>Какую проблему мы <em>решаем</em>? Правда ли, что решение, которое мы предлагаем, действительно решает проблему? Не создаём ли мы на её месте другую проблему, более сложную?</p></li>
|
<li><p>Какую проблему мы <em>решаем</em>? Правда ли, что решение, которое мы предлагаем, действительно решает проблему? Не создаём ли мы на её месте другую проблему, более сложную?</p></li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Итак, предположим, что мы хотим предоставить API автоматического заказа кофе в городских кофейнях. Попробуем применить к ней этот принцип.</p>
|
<p>Итак, предположим, что мы хотим предоставить API автоматического заказа кофе в городских кофейнях. Попробуем применить к нему этот принцип.</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Зачем кому-то может потребоваться API для приготовления кофе? В чем неудобство заказа кофе через интерфейс, человек-человек или человек-машина? Зачем нужна возможность заказа машина-машина?</p>
|
<li><p>Зачем кому-то может потребоваться API для приготовления кофе? В чем неудобство заказа кофе через интерфейс, человек-человек или человек-машина? Зачем нужна возможность заказа машина-машина?</p>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -212,14 +212,14 @@ Cache-Control: no-cache
|
|||||||
<p>На все эти вопросы, в общем случае, простого ответа нет. В идеале ответы на эти вопросы должны даваться с цифрами в руках. Сколько конкретно времени тратится неоптимально, и какого значения мы рассчитываем добиться, располагая какой плотностью кофе-машин? Заметим также, что в реальной жизни просчитать такого рода цифры можно в основном для проектов, которые пытаются влезть на уже устоявшийся рынок; если вы пытаетесь сделать что-то новое, то, вероятно, вам придётся ориентироваться в основном на свою интуицию.</p>
|
<p>На все эти вопросы, в общем случае, простого ответа нет. В идеале ответы на эти вопросы должны даваться с цифрами в руках. Сколько конкретно времени тратится неоптимально, и какого значения мы рассчитываем добиться, располагая какой плотностью кофе-машин? Заметим также, что в реальной жизни просчитать такого рода цифры можно в основном для проектов, которые пытаются влезть на уже устоявшийся рынок; если вы пытаетесь сделать что-то новое, то, вероятно, вам придётся ориентироваться в основном на свою интуицию.</p>
|
||||||
<h4 id="api">Почему API?</h4>
|
<h4 id="api">Почему API?</h4>
|
||||||
<p>Т.к. наша книга посвящена не просто разработке программного обеспечения, а разработке API, то на все эти вопросы мы должны взглянуть под другим ракурсом: а почему для решения этих задач требуется именно API, а не просто программное обеспечение? В нашем вымышленном примере мы должны спросить себя: зачем нам нужно предоставлять сервис для других разработчиков, чтобы они могли готовить кофе своим клиентам, а не сделать своё приложение для конечного потребителя?</p>
|
<p>Т.к. наша книга посвящена не просто разработке программного обеспечения, а разработке API, то на все эти вопросы мы должны взглянуть под другим ракурсом: а почему для решения этих задач требуется именно API, а не просто программное обеспечение? В нашем вымышленном примере мы должны спросить себя: зачем нам нужно предоставлять сервис для других разработчиков, чтобы они могли готовить кофе своим клиентам, а не сделать своё приложение для конечного потребителя?</p>
|
||||||
<p>Иными словами, должна иметься веская причина, по которой два домена разработки ПО должны быть разделены: есть оператор(ы), предоставляющий API; есть оператор(ы), предоставляющий сервисы пользователям. Их интересы в чем-то различны настолько, что объединение этих двух ролей в одном лице нежелательно. Более подробно мы изложим причины и мотивации делать именно API в разделе II.</p>
|
<p>Иными словами, должна иметься веская причина, по которой два домена разработки ПО должны быть разделены: есть оператор(ы), предоставляющий API; есть оператор(ы), предоставляющий сервисы пользователям. Их интересы в чем-то различны настолько, что объединение этих двух ролей в одном лице нежелательно. Более подробно мы изложим причины и мотивации делать именно API в разделе III.</p>
|
||||||
<p>Заметим также следующее: вы должны браться делать API тогда и только тогда, когда в ответе на второй вопрос написали «потому что в этом состоит наша экспертиза». Разрабатывая API вы занимаетесь некоторой мета-разработкой: вы пишете ПО для того, чтобы другие могли разрабатывать ПО для решения задачи пользователя. Не обладая экспертизой в обоих этих доменах (API и конечные продукты) написать хорошее API сложно.</p>
|
<p>Заметим также следующее: вы должны браться делать API тогда и только тогда, когда в ответе на второй вопрос написали «потому что в этом состоит наша экспертиза». Разрабатывая API вы занимаетесь некоторой мета-разработкой: вы пишете ПО для того, чтобы другие могли разрабатывать ПО для решения задачи пользователя. Не обладая экспертизой в обоих этих доменах (API и конечные продукты) написать хорошее API сложно.</p>
|
||||||
<p>Для нашего умозрительного примера предположим, что в недалеком будущем произошло разделение рынка кофе на две группы игроков: одни предоставляют само железо, кофейные аппараты, а другие имеют доступ к потребителю — примерно как это произошло, например, с рынком авиабилетов, где есть собственно авиакомпании, осуществляющие перевозку, и сервисы планирования путешествий, где люди выбирают варианты перелётов. Мы хотим агрегировать доступ к железу, чтобы владельцы приложений могли встраивать заказ кофе.</p>
|
<p>Для нашего умозрительного примера предположим, что в недалеком будущем произошло разделение рынка кофе на две группы игроков: одни предоставляют само железо, кофейные аппараты, а другие имеют доступ к потребителю — примерно как это произошло, например, с рынком авиабилетов, где есть собственно авиакомпании, осуществляющие перевозку, и сервисы планирования путешествий, где люди выбирают варианты перелётов. Мы хотим агрегировать доступ к железу, чтобы владельцы приложений могли встраивать заказ кофе.</p>
|
||||||
<h4 id="">Что и как</h4>
|
<h4 id="">Что и как</h4>
|
||||||
<p>Закончив со всеми теоретическими упражнениями, мы должны перейти непосредственно к дизайну и разработке API, имея понимание по двум пунктам:</p>
|
<p>Закончив со всеми теоретическими упражнениями, мы должны перейти непосредственно к дизайну и разработке API, имея понимание по двум пунктам.</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Что конкретно мы делаем</li>
|
<li>Что конкретно мы делаем.</li>
|
||||||
<li>Как мы это делаем</li>
|
<li>Как мы это делаем.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>В случае нашего кофе-примера мы:</p>
|
<p>В случае нашего кофе-примера мы:</p>
|
||||||
<ol>
|
<ol>
|
||||||
@@ -855,25 +855,25 @@ POST /v1/orders/statistics/aggregate
|
|||||||
<p>Два важных следствия:</p>
|
<p>Два важных следствия:</p>
|
||||||
<p><strong>1.1.</strong> Если операция модифицирующая, это должно быть очевидно из сигнатуры. В частности, не может быть модифицирующих операций за <code>GET</code>.</p>
|
<p><strong>1.1.</strong> Если операция модифицирующая, это должно быть очевидно из сигнатуры. В частности, не может быть модифицирующих операций за <code>GET</code>.</p>
|
||||||
<p><strong>1.2.</strong> Если в номенклатуре вашего API есть как синхронные операции, так и асинхронные, то (а)синхронность должна быть очевидна из сигнатур, <strong>либо</strong> должна существовать конвенция именования, позволяющая отличать синхронные операции от асинхронных.</p>
|
<p><strong>1.2.</strong> Если в номенклатуре вашего API есть как синхронные операции, так и асинхронные, то (а)синхронность должна быть очевидна из сигнатур, <strong>либо</strong> должна существовать конвенция именования, позволяющая отличать синхронные операции от асинхронных.</p>
|
||||||
<h4 id="2">2. Использованные стандарты указывайте явно</h4>
|
<h4 id="2">2. Указывайте использованные стандарты</h4>
|
||||||
<p>К сожалению, человечество не в состоянии договориться о таких простейших вещах, как «с какого дня начинается неделя», что уж говорить о каких-то более сложных стандартах.</p>
|
<p>К сожалению, человечество не в состоянии договориться о таких простейших вещах, как «с какого дня начинается неделя», что уж говорить о каких-то более сложных стандартах.</p>
|
||||||
<p>Поэтому <em>всегда</em> указывайте, по какому конкретно стандарту вы отдаёте те или иные величины. Исключения возможны только там, где вы на 100% уверены, что в мире существует только один стандарт для этой сущности, и всё население земного шара о нём в курсе.</p>
|
<p>Поэтому <em>всегда</em> указывайте, по какому конкретно стандарту вы отдаёте те или иные величины. Исключения возможны только там, где вы на 100% уверены, что в мире существует только один стандарт для этой сущности, и всё население земного шара о нём в курсе.</p>
|
||||||
<p><strong>Плохо</strong>: <code>"date":"11/12/2020"</code> — стандартов записи дат существует огромное количество, плюс из этой записи невозможно даже понять, что здесь число, а что месяц.</p>
|
<p><strong>Плохо</strong>: <code>"date": "11/12/2020"</code> — стандартов записи дат существует огромное количество, плюс из этой записи невозможно даже понять, что здесь число, а что месяц.</p>
|
||||||
<p><strong>Хорошо</strong>: <code>"iso_date":"2020-11-12"</code>.</p>
|
<p><strong>Хорошо</strong>: <code>"iso_date": "2020-11-12"</code>.</p>
|
||||||
<p><strong>Плохо</strong>: <code>"duration":5000</code> — пять тысяч чего?</p>
|
<p><strong>Плохо</strong>: <code>"duration": 5000</code> — пять тысяч чего?</p>
|
||||||
<p><strong>Хорошо</strong>:<br />
|
<p><strong>Хорошо</strong>:<br />
|
||||||
<code>"duration_ms":5000</code><br />
|
<code>"duration_ms": 5000</code><br />
|
||||||
либо<br />
|
либо<br />
|
||||||
<code>"duration":"5000ms"</code><br />
|
<code>"duration": "5000ms"</code><br />
|
||||||
либо<br />
|
либо<br />
|
||||||
<code>"duration":{"unit":"ms","value":5000}</code>.</p>
|
<code>"duration": {"unit": "ms", "value": 5000}</code>.</p>
|
||||||
<p>Отдельное следствие из этого правила — денежные величины <em>всегда</em> должны сопровождаться указанием кода валюты.</p>
|
<p>Отдельное следствие из этого правила — денежные величины <em>всегда</em> должны сопровождаться указанием кода валюты.</p>
|
||||||
<p>Также следует отметить, что в некоторых областях ситуация со стандартами настолько плоха, что как ни сделай — кто-то останется недовольным. Классический пример такого рода — порядок географических координат ("широта-долгота" против "долгота-широта"). Здесь, увы, есть только один работающий метод борьбы с фрустрацией — «блокнот душевного спокойствия», который будет описан в разделе II.</p>
|
<p>Также следует отметить, что в некоторых областях ситуация со стандартами настолько плоха, что как ни сделай — кто-то останется недовольным. Классический пример такого рода — порядок географических координат ("широта-долгота" против "долгота-широта"). Здесь, увы, есть только один работающий метод борьбы с фрустрацией — «блокнот душевного спокойствия», который будет описан в разделе II.</p>
|
||||||
<h4 id="3">3. Сохраняйте точность дробных чисел</h4>
|
<h4 id="3">3. Сохраняйте точность дробных чисел</h4>
|
||||||
<p>Там, где это позволено протоколом, дробные числа с фиксированной запятой — такие, как денежные суммы, например — должны передаваться в виде специально предназначенных для этого объектов, например, Decimal или аналогичных.</p>
|
<p>Там, где это позволено протоколом, дробные числа с фиксированной запятой — такие, как денежные суммы, например — должны передаваться в виде специально предназначенных для этого объектов, например, Decimal или аналогичных.</p>
|
||||||
<p>Если в протоколе нет Decimal-типов (в частности, в JSON нет чисел с фиксированной запятой), следует либо привести к целому (путём домножения на указанный множитель), либо использовать строковый тип.</p>
|
<p>Если в протоколе нет Decimal-типов (в частности, в JSON нет чисел с фиксированной запятой), следует либо привести к целому (путём домножения на указанный множитель), либо использовать строковый тип.</p>
|
||||||
<h4 id="4">4. Сущности должны именоваться конкретно</h4>
|
<h4 id="4">4. Сущности должны именоваться конкретно</h4>
|
||||||
<p>Избегайте слов-«амёб» без определённой семантики, таких как get, apply, make. Сущности должны именоваться конкретно.</p>
|
<p>Избегайте одиночных слов-«амёб» без определённой семантики, таких как get, apply, make.</p>
|
||||||
<p><strong>Плохо</strong>: <code>user.get()</code> — неочевидно, что конкретно будет возвращено.</p>
|
<p><strong>Плохо</strong>: <code>user.get()</code> — неочевидно, что конкретно будет возвращено.</p>
|
||||||
<p><strong>Хорошо</strong>: <code>user.get_id()</code>.</p>
|
<p><strong>Хорошо</strong>: <code>user.get_id()</code>.</p>
|
||||||
<h4 id="5">5. Не экономьте буквы</h4>
|
<h4 id="5">5. Не экономьте буквы</h4>
|
||||||
@@ -890,7 +890,7 @@ strpbrk (str1, str2)
|
|||||||
— однако необходимость существования такого метода вообще вызывает сомнения, достаточно было бы иметь удобную функцию поиска подстроки с нужными параметрами. Аналогично сокращение <code>string</code> до <code>str</code> выглядит совершенно бессмысленным, но, увы, является устоявшимся для большого количества предметных областей.</p>
|
— однако необходимость существования такого метода вообще вызывает сомнения, достаточно было бы иметь удобную функцию поиска подстроки с нужными параметрами. Аналогично сокращение <code>string</code> до <code>str</code> выглядит совершенно бессмысленным, но, увы, является устоявшимся для большого количества предметных областей.</p>
|
||||||
<h4 id="6">6. Тип поля должен быть ясен из его названия</h4>
|
<h4 id="6">6. Тип поля должен быть ясен из его названия</h4>
|
||||||
<p>Если поле называется <code>recipe</code> — мы ожидаем, что его значением является сущность типа <code>Recipe</code>. Если поле называется <code>recipe_id</code> — мы ожидаем, что его значением является идентификатор, который мы сможем найти в составе сущности <code>Recipe</code>.</p>
|
<p>Если поле называется <code>recipe</code> — мы ожидаем, что его значением является сущность типа <code>Recipe</code>. Если поле называется <code>recipe_id</code> — мы ожидаем, что его значением является идентификатор, который мы сможем найти в составе сущности <code>Recipe</code>.</p>
|
||||||
<p>Сущности-массивы должны именоваться во множественном числе или собирательными выражениями — <code>objects</code>, <code>children</code>; если это невозможно (термин неисчисляемый), следует добавить префикс или постфикс, не оставляющий сомнений.</p>
|
<p>То же касается и примитивных типов. Сущности-массивы должны именоваться во множественном числе или собирательными выражениями — <code>objects</code>, <code>children</code>; если это невозможно (термин неисчисляемый), следует добавить префикс или постфикс, не оставляющий сомнений.</p>
|
||||||
<p><strong>Плохо</strong>: <code>GET /news</code> — неясно, будет ли получена какая-то конкретная новость или массив новостей.</p>
|
<p><strong>Плохо</strong>: <code>GET /news</code> — неясно, будет ли получена какая-то конкретная новость или массив новостей.</p>
|
||||||
<p><strong>Хорошо</strong>: <code>GET /news-list</code>.</p>
|
<p><strong>Хорошо</strong>: <code>GET /news-list</code>.</p>
|
||||||
<p>Аналогично, если ожидается булево значение, то из названия это должно быть очевидно, т.е. именование должно описывать некоторое качественное состояние, например, <code>is_ready</code>, <code>open_now</code>.</p>
|
<p>Аналогично, если ожидается булево значение, то из названия это должно быть очевидно, т.е. именование должно описывать некоторое качественное состояние, например, <code>is_ready</code>, <code>open_now</code>.</p>
|
||||||
|
BIN
docs/API.ru.pdf
BIN
docs/API.ru.pdf
Binary file not shown.
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
Здесь и далее мы будем придерживаться принципов версионирования [semver](https://semver.org/):
|
Здесь и далее мы будем придерживаться принципов версионирования [semver](https://semver.org/):
|
||||||
|
|
||||||
1. Версия API задаётся тремя цифрами, вида `1.2.3`
|
1. Версия API задаётся тремя цифрами, вида `1.2.3`.
|
||||||
2. Первая цифра (мажорная версия) увеличивается при обратно несовместимых изменениях в API
|
2. Первая цифра (мажорная версия) увеличивается при обратно несовместимых изменениях в API.
|
||||||
3. Вторая цифра (минорная версия) увеличивается при добавлении новой функциональности с сохранением обратной совместимости
|
3. Вторая цифра (минорная версия) увеличивается при добавлении новой функциональности с сохранением обратной совместимости.
|
||||||
4. Третья цифра (патч) увеличивается при выпуске новых версий, содержащих только исправление ошибок
|
4. Третья цифра (патч) увеличивается при выпуске новых версий, содержащих только исправление ошибок.
|
||||||
|
|
||||||
Выражения «мажорная версия API» и «версия API, содержащая обратно несовместимые изменения функциональности» тем самым следует считать эквивалентными.
|
Выражения «мажорная версия API» и «версия API, содержащая обратно несовместимые изменения функциональности» тем самым следует считать эквивалентными.
|
||||||
|
|
||||||
|
@@ -28,10 +28,10 @@ Cache-Control: no-cache
|
|||||||
|
|
||||||
Её следует читать так:
|
Её следует читать так:
|
||||||
* выполняется POST-запрос к ресурсу `/v1/bucket/{id}/some-resource`, где `{id}` заменяется на некоторый идентификатор `bucket`-а (при отсутствии уточнений подстановки вида `{something}` следует относить к ближайшему термину слева);
|
* выполняется POST-запрос к ресурсу `/v1/bucket/{id}/some-resource`, где `{id}` заменяется на некоторый идентификатор `bucket`-а (при отсутствии уточнений подстановки вида `{something}` следует относить к ближайшему термину слева);
|
||||||
* запрос сопровождается (помимо стандартных заголовков, которые мы опускаем) дополнительным заголовком X-Idempotency-Token;
|
* запрос сопровождается (помимо стандартных заголовков, которые мы опускаем) дополнительным заголовком `X-Idempotency-Token`;
|
||||||
* фразы в угловых скобках (`<токен идемпотентности>`) описывают семантику значения сущности (поля, заголовка, параметра);
|
* фразы в угловых скобках (`<токен идемпотентности>`) описывают семантику значения сущности (поля, заголовка, параметра);
|
||||||
* в качестве тела запроса передаётся JSON, содержащий поле `some_parameter` со значением `value` и ещё какие-то поля, которые для краткости опущены (что показано многоточием);
|
* в качестве тела запроса передаётся JSON, содержащий поле `some_parameter` со значением `value` и ещё какие-то поля, которые для краткости опущены (что показано многоточием);
|
||||||
* в ответ (индицируется стрелкой `→`) сервер возвращает статус 404 Not Found; статус может быть опущен (отсутствие статуса следует трактовать как `200 OK`);
|
* в ответ (индицируется стрелкой `→`) сервер возвращает статус `404 Not Found`; статус может быть опущен (отсутствие статуса следует трактовать как `200 OK`);
|
||||||
* в ответе также могут находиться дополнительные заголовки, на которые мы обращаем внимание;
|
* в ответе также могут находиться дополнительные заголовки, на которые мы обращаем внимание;
|
||||||
* телом ответа является JSON, состоящий из единственного поля `error_message`; отсутствие значения поля означает, что его значением является именно то, что в этом поле и ожидается — в данном случае какое-то сообщение об ошибке.
|
* телом ответа является JSON, состоящий из единственного поля `error_message`; отсутствие значения поля означает, что его значением является именно то, что в этом поле и ожидается — в данном случае какое-то сообщение об ошибке.
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
4. Какую проблему мы _решаем_? Правда ли, что решение, которое мы предлагаем, действительно решает проблему? Не создаём ли мы на её месте другую проблему, более сложную?
|
4. Какую проблему мы _решаем_? Правда ли, что решение, которое мы предлагаем, действительно решает проблему? Не создаём ли мы на её месте другую проблему, более сложную?
|
||||||
|
|
||||||
Итак, предположим, что мы хотим предоставить API автоматического заказа кофе в городских кофейнях. Попробуем применить к ней этот принцип.
|
Итак, предположим, что мы хотим предоставить API автоматического заказа кофе в городских кофейнях. Попробуем применить к нему этот принцип.
|
||||||
|
|
||||||
1. Зачем кому-то может потребоваться API для приготовления кофе? В чем неудобство заказа кофе через интерфейс, человек-человек или человек-машина? Зачем нужна возможность заказа машина-машина?
|
1. Зачем кому-то может потребоваться API для приготовления кофе? В чем неудобство заказа кофе через интерфейс, человек-человек или человек-машина? Зачем нужна возможность заказа машина-машина?
|
||||||
* Возможно, мы хотим решить проблему выбора и знания? Чтобы человек наиболее полно знал о доступных ему здесь и сейчас опциях.
|
* Возможно, мы хотим решить проблему выбора и знания? Чтобы человек наиболее полно знал о доступных ему здесь и сейчас опциях.
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
Т.к. наша книга посвящена не просто разработке программного обеспечения, а разработке API, то на все эти вопросы мы должны взглянуть под другим ракурсом: а почему для решения этих задач требуется именно API, а не просто программное обеспечение? В нашем вымышленном примере мы должны спросить себя: зачем нам нужно предоставлять сервис для других разработчиков, чтобы они могли готовить кофе своим клиентам, а не сделать своё приложение для конечного потребителя?
|
Т.к. наша книга посвящена не просто разработке программного обеспечения, а разработке API, то на все эти вопросы мы должны взглянуть под другим ракурсом: а почему для решения этих задач требуется именно API, а не просто программное обеспечение? В нашем вымышленном примере мы должны спросить себя: зачем нам нужно предоставлять сервис для других разработчиков, чтобы они могли готовить кофе своим клиентам, а не сделать своё приложение для конечного потребителя?
|
||||||
|
|
||||||
Иными словами, должна иметься веская причина, по которой два домена разработки ПО должны быть разделены: есть оператор(ы), предоставляющий API; есть оператор(ы), предоставляющий сервисы пользователям. Их интересы в чем-то различны настолько, что объединение этих двух ролей в одном лице нежелательно. Более подробно мы изложим причины и мотивации делать именно API в разделе II.
|
Иными словами, должна иметься веская причина, по которой два домена разработки ПО должны быть разделены: есть оператор(ы), предоставляющий API; есть оператор(ы), предоставляющий сервисы пользователям. Их интересы в чем-то различны настолько, что объединение этих двух ролей в одном лице нежелательно. Более подробно мы изложим причины и мотивации делать именно API в разделе III.
|
||||||
|
|
||||||
Заметим также следующее: вы должны браться делать API тогда и только тогда, когда в ответе на второй вопрос написали «потому что в этом состоит наша экспертиза». Разрабатывая API вы занимаетесь некоторой мета-разработкой: вы пишете ПО для того, чтобы другие могли разрабатывать ПО для решения задачи пользователя. Не обладая экспертизой в обоих этих доменах (API и конечные продукты) написать хорошее API сложно.
|
Заметим также следующее: вы должны браться делать API тогда и только тогда, когда в ответе на второй вопрос написали «потому что в этом состоит наша экспертиза». Разрабатывая API вы занимаетесь некоторой мета-разработкой: вы пишете ПО для того, чтобы другие могли разрабатывать ПО для решения задачи пользователя. Не обладая экспертизой в обоих этих доменах (API и конечные продукты) написать хорошее API сложно.
|
||||||
|
|
||||||
@@ -41,10 +41,10 @@
|
|||||||
|
|
||||||
#### Что и как
|
#### Что и как
|
||||||
|
|
||||||
Закончив со всеми теоретическими упражнениями, мы должны перейти непосредственно к дизайну и разработке API, имея понимание по двум пунктам:
|
Закончив со всеми теоретическими упражнениями, мы должны перейти непосредственно к дизайну и разработке API, имея понимание по двум пунктам.
|
||||||
|
|
||||||
1. Что конкретно мы делаем
|
1. Что конкретно мы делаем.
|
||||||
2. Как мы это делаем
|
2. Как мы это делаем.
|
||||||
|
|
||||||
В случае нашего кофе-примера мы:
|
В случае нашего кофе-примера мы:
|
||||||
|
|
||||||
|
@@ -53,24 +53,24 @@ POST /v1/orders/statistics/aggregate
|
|||||||
|
|
||||||
**1.2.** Если в номенклатуре вашего API есть как синхронные операции, так и асинхронные, то (а)синхронность должна быть очевидна из сигнатур, **либо** должна существовать конвенция именования, позволяющая отличать синхронные операции от асинхронных.
|
**1.2.** Если в номенклатуре вашего API есть как синхронные операции, так и асинхронные, то (а)синхронность должна быть очевидна из сигнатур, **либо** должна существовать конвенция именования, позволяющая отличать синхронные операции от асинхронных.
|
||||||
|
|
||||||
#### 2. Использованные стандарты указывайте явно
|
#### 2. Указывайте использованные стандарты
|
||||||
|
|
||||||
К сожалению, человечество не в состоянии договориться о таких простейших вещах, как «с какого дня начинается неделя», что уж говорить о каких-то более сложных стандартах.
|
К сожалению, человечество не в состоянии договориться о таких простейших вещах, как «с какого дня начинается неделя», что уж говорить о каких-то более сложных стандартах.
|
||||||
|
|
||||||
Поэтому _всегда_ указывайте, по какому конкретно стандарту вы отдаёте те или иные величины. Исключения возможны только там, где вы на 100% уверены, что в мире существует только один стандарт для этой сущности, и всё население земного шара о нём в курсе.
|
Поэтому _всегда_ указывайте, по какому конкретно стандарту вы отдаёте те или иные величины. Исключения возможны только там, где вы на 100% уверены, что в мире существует только один стандарт для этой сущности, и всё население земного шара о нём в курсе.
|
||||||
|
|
||||||
**Плохо**: `"date":"11/12/2020"` — стандартов записи дат существует огромное количество, плюс из этой записи невозможно даже понять, что здесь число, а что месяц.
|
**Плохо**: `"date": "11/12/2020"` — стандартов записи дат существует огромное количество, плюс из этой записи невозможно даже понять, что здесь число, а что месяц.
|
||||||
|
|
||||||
**Хорошо**: `"iso_date":"2020-11-12"`.
|
**Хорошо**: `"iso_date": "2020-11-12"`.
|
||||||
|
|
||||||
**Плохо**: `"duration":5000` — пять тысяч чего?
|
**Плохо**: `"duration": 5000` — пять тысяч чего?
|
||||||
|
|
||||||
**Хорошо**:
|
**Хорошо**:
|
||||||
`"duration_ms":5000`
|
`"duration_ms": 5000`
|
||||||
либо
|
либо
|
||||||
`"duration":"5000ms"`
|
`"duration": "5000ms"`
|
||||||
либо
|
либо
|
||||||
`"duration":{"unit":"ms","value":5000}`.
|
`"duration": {"unit": "ms", "value": 5000}`.
|
||||||
|
|
||||||
Отдельное следствие из этого правила — денежные величины *всегда* должны сопровождаться указанием кода валюты.
|
Отдельное следствие из этого правила — денежные величины *всегда* должны сопровождаться указанием кода валюты.
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ POST /v1/orders/statistics/aggregate
|
|||||||
|
|
||||||
#### 4. Сущности должны именоваться конкретно
|
#### 4. Сущности должны именоваться конкретно
|
||||||
|
|
||||||
Избегайте слов-«амёб» без определённой семантики, таких как get, apply, make. Сущности должны именоваться конкретно.
|
Избегайте одиночных слов-«амёб» без определённой семантики, таких как get, apply, make.
|
||||||
|
|
||||||
**Плохо**: `user.get()` — неочевидно, что конкретно будет возвращено.
|
**Плохо**: `user.get()` — неочевидно, что конкретно будет возвращено.
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ strpbrk (str1, str2)
|
|||||||
|
|
||||||
Если поле называется `recipe` — мы ожидаем, что его значением является сущность типа `Recipe`. Если поле называется `recipe_id` — мы ожидаем, что его значением является идентификатор, который мы сможем найти в составе сущности `Recipe`.
|
Если поле называется `recipe` — мы ожидаем, что его значением является сущность типа `Recipe`. Если поле называется `recipe_id` — мы ожидаем, что его значением является идентификатор, который мы сможем найти в составе сущности `Recipe`.
|
||||||
|
|
||||||
Сущности-массивы должны именоваться во множественном числе или собирательными выражениями — `objects`, `children`; если это невозможно (термин неисчисляемый), следует добавить префикс или постфикс, не оставляющий сомнений.
|
То же касается и примитивных типов. Сущности-массивы должны именоваться во множественном числе или собирательными выражениями — `objects`, `children`; если это невозможно (термин неисчисляемый), следует добавить префикс или постфикс, не оставляющий сомнений.
|
||||||
|
|
||||||
**Плохо**: `GET /news` — неясно, будет ли получена какая-то конкретная новость или массив новостей.
|
**Плохо**: `GET /news` — неясно, будет ли получена какая-то конкретная новость или массив новостей.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user