Комментарии 41
Под каждую версию API держите свою ветку?
Или поддерживаете все версии внутри одной кодовой базы?
После появления новой версии, старая снимается с поддержки даже с багфиксрв.
Обычно у нас версия 1 — это рабочий прототип на php, а 2ая это полноценная версия на C++. Далее изменения уже не требуются.
Ну и читайте статью — https://megamozg.ru/post/24718/, там все ответы
Добавлю также от себя:
- Все методы, изменяющие состояние, будь то в БД или in-memory, должны быть как минимум POST, или же детализироваться — PUT/DELETE
- Есть критические бизнес-функции, требующие не только некоего входного набора параметров — но и, скажем некоей проверочной контрольной суммы на ключевые поля добавляемой сущности. Скажем так, checksum token в таких методах — это очередная линия обороны против плохо составленных запросов.
- Отдельные части location'а должны быть как можно более краткими. Скажем, для случая если вы запрашиваете информацию по товару — /products/get/{id}, а не /get-product/{id}
Большая часть советов по обходу граблей REST API была описана еще в статье от Яндекса
https://habrahabr.ru/company/yandex/blog/265569/
Я даже делал клиентсткую REST-библиотеку для Qt (доступен здесь https://github.com/kafeg/qtrest), которая основана на философии Yii2 REST API.
Как там реализовано версионирование?
В каждом модуле — набор контроллеров, которые используют единый набор моделей данных.
При создании новой версии API — наследуем все контроллеры от контроллеров предыдущей версии, внося необходимые изменения в каждый новый контроллер.
Таким образом, поддержка в работоспособном виде всех версий заключается в правке нужного контроллера в последней или одной из промежуточных версий API.
Например: https://github.com/githubjeka/yii2-rest/blob/master/rest/versions/v2/controllers/PostController.php
Это делается автоматом, или надо делать руками? Что делать, если я не хочу, чтобы у разных версий были одинаковые DTO?
2. Сгенерируйте новую модель.
Наследование руками, но можно набросать пару скриптов.
Ну значит тезис "Все элементарно просто и при этом функционально и соответствует стандартам и лучшим практикам" — неверен, потому что как минимум версионирование делается так, как этого хочет разработчик. Не удивлюсь, если и с остальными мелкими нюансами так окажется.
Вы ознакомьтесь с фреймворком для начала, а затем делайте выводы, а то выходит я Вам предлагаю на альтернативу глянуть, а Вы ничего не прочитав, сразу «твои тезисы отстой, пошел вон со своими комментами».
Ну ок, давайте разберемся, почему Ваша статья неверна с моей точки зрения.
Во первых в разработке Yii/Django и других фреймворков участвуют далеко не идиоты. Во вторых, я набил немало шишек при разработке и использовании API на разных языках, с обоих сторон и имею представление, какое API могут предоставить заказчики.
А во вторых Вы хвастаетесь что написали уже 100-е API, но при этом:
— пишете о валидации. На дворе 2016 год. Что у вас за фреймворк что не умеет валидацию на уровне моделей? А если умеет — то зачем валидация в API? Вы что не описываете правила валидации в каждой модели, а выносите это в API? А потом дублируете, если в проекте кроме API еще есть и Web-морда? А почему тогда Вы не пишете о других вещах, которыми занимаются модели? Например поведения (behaviour)?
— пишете о логировании. Так и чего, какие параметры запросов/ответов логировать? Если не иметь представления и прочитать лишь вашу статью — то наверное «url, тело запроса, тело ответа, код ответа сервера». А как же заголовки запросов/ответов, дата и время запроса, user-agent устройства? Вы же 100 API написали, ни разу не понадобилось? А почему вы не написали о том что и как логировать при загрузке файлов на сервер? А как версионировать логи и удалять старые? А нужны ли уровни логирования и как их использовать? У Вас есть практики на эти случаи?
— далее, версионарование АПИ и тезис из Вашего коммента. " как минимум версионирование делается так, как этого хочет разработчик". Я не понял что вы хотите сказать то? Разработчик имеет полную свободу — хочешь копируй или наследуй контроллеры руками, а не хочешь — напиши простой скрипт на Bash который это сделает за тебя.
— Вы сделали 100 API, но после Вашей статьи в комментариях люди делают замечание — НЕ ИСПОЛЬЗУЙТЕ GET МЕТОД ДЛЯ ИЗМЕНЕНИЯ СОСТОЯНИЯ СЕРВЕРА. Да йопт, это чуть ли не самый главный тезис который нужно понять в жизни при разработке API чего угодно. А Вы этого не поняли? Или не захотели рассказать?
— К 100-му API Вы поняли, какой формат данных лучше использовать — JSON или XML? Да? Почему не написали? Нет? Да как нет, Вы же 100 API уже написали!
— документация. Фактически, Вы говорите прямо: пишите документацию руками, не используйте Swagger. Ок, предложите, как тестировать и читать доку к API, не имея Swagger? Внешними инструментами? То есть мне нужно писать документацию в системе управления проектами, копировать ее периодически в сорцы и затем еще использовать сторонние приблуды для тестирования API? ну и де тут продуктивность? А вот пример — доку веду я, как менеджер проекта. Девелопер мне скидывает список кодов ответа сервера на один из методов, я их заношу в доку. Через день девелопер меняет коды ответов, и… забывает сообщить мне/у меня запара/сообщение etc… Дока бац и неактуальна! Или я все же внес его правки в доку, а потом бац и коммит в гите откатил другой, более опытный девелопер, которому не понравился код на код-ревью — опять дока неактуальна. Ну и шо делать? Запомните — документация API должна всегда следовать за кодом и по мере возможности, всегда генерироваться автоматически, после каждого очередного билда. А если там HATEOAS, то о документации вообзе можно не думать, ибо все по стандарту.
— пагинация. О да! Это тоже одна из интереснейших вещей. Вы ни разу не использовали ее? Или еще не поняли как правильно? Где совет? Нахрен в интернете статья, которая говорит «мы написали 100 апи, мы ВСЕЕЕЕ поняли!!!» и в которой ни слова о пейджинге данных? А между тем их существует аж несколько видов, почитайте на досуге: http://www.django-rest-framework.org/api-guide/pagination/
— сортировка, фильтрация данных. Где? Как лучше? Посоветуйте? Не вижу!!!
— «Соблюдайте протокол (как минимум Status Code)». И что? Ну где хоть пример протокола? Хоть за что зацепиться? Вот не знаю я например с чего вообще начать написание API, какой я протокол сам придумаю?
— etc…
Так вот.
1. Я считаю Вашу статью абсолютно не состоятельной и бесполезной, а Ваши тезисы и советы — непроработанными. Я посоветовал Вам ознакомиться с нормальной практикой и решил не указывать на огрехи. Но, вместо того, чтобы последовать совету или забить, Вы решили голословно меня послать. Ловите ответ.
2. Вы обещали методологию, выработанную на реальном опыте. А в статье лишь теория, причем плохая.
Дискуссию продолжать не буду.
Вы ознакомьтесь с фреймворком для начала, а затем делайте выводы [...] Ну ок, давайте разберемся, почему Ваша статья неверна с моей точки зрения.
Вы для начала посмотрите, с кем вы переписываетесь, а затем делайте выводы.
далее, версионарование АПИ и тезис из Вашего коммента. " как минимум версионирование делается так, как этого хочет разработчик". Я не понял что вы хотите сказать то?
Я хочу сказать очень простую вещь: в Yii2 нет — или я не нашел по вашему описанию — никакой реализации версионирования. Просто нет такой концепции. Следовательно, Yii2 не определяет, как именно будет сделано версионирование, за это отвечает разработчик. А, следовательно, какой шаблон разработчик выберет, такой и получится.
документация API должна всегда следовать за кодом и по мере возможности, всегда генерироваться автоматически, после каждого очередного билда. А если там HATEOAS, то о документации вообзе можно не думать, ибо все по стандарту.
С этого места, пожалуйста, поподробнее — по какому именно стандарту?
в Yii2 нет — или я не нашел по вашему описанию — никакой реализации версионирования.
Так и есть. Разработчику предлагается сделать то, что вы описали в своем комментарии, используя стандартные концепции — то есть модуль вместо версии.
— документация всегда актуальна
— документация всегда под рукой (если ты можешь обращаться к микросервису, ты можешь сделать GET /api в браузере)
— и, в результате, мнгновенный ответ на вопросы типа «а что вообще умеет эта штука, которую мы два года назад написали?» и «подзабыл название поля в API, как быстро посмотреть»
Спасибо!
Мы начинали со swagger, но в итоге от него отказались — его спецификация до сих пор реализована только частично и качество инструментария, мягко говоря, не очень хорошее.
Результат выглядит примерно так:
summary("API call summary")
description("long, possibly multiline description of this API call"
pathParam[String]("db", "current database name")
pathParam[String]("coll", "current collection")
queryParam[Int]("offset", "current paging offset")
queryParam[Int]("limit", "number of elements per page")
produces[MyResponseTO]("application/javascript")
get("/db/{db}/coll/{coll}", (db, coll) => { ..... Future successful response })
Документация почти всегда не актуальна, а инструменты вроде swagger все равно требуют поддержки.
Вот тут можно чуть подробнее? О какой именно поддержке Сваггера вы говорите?
А решение с постановкой задачи в виде доки — исключает любые факторы и не завязано на инструменты.
Нет, подождите. Я не знаю, о какой разметке вы говорите (у нас, например, это просто часть апи: нельзя выкатить незадокументированный метод), но дело даже не в этом. В любом случае же нужны какие-то усилия на документирование. И если я правильно понял (а я не исключаю, что понял неправильно), то вы предлагаете копировать документацию из одного места в другое («Выложите новый метод на боевой сервер — просто скопируете документацию из задачи в ваше хранилище документации.»). И теперь у вас два источника одной информации. Проблема в том, что документацию часто приходится дополнять, поправлять. Теперь на каждую правку нужно делать ещё и копирование, о котором забыть гораздо проще.
В целом то, что вы описываете, больше похоже на «сначала досканально спроектируйте метод апи, включая техническое проектирование, а затем — реализуйте». То есть, на этапе проектирования вы уже его документируете. Это всё правильно, да. Но что мешает затем документацию закрепить за методом и не копипастить повсюду? Сваггер и ему подобные инструменты как раз позволяют это сделать.
Документация к методу API — это же не только его название и набор параметров. Как минимум описание «что? зачем? когда нельзя использовать? когда нужно?». Ведь иначе новый человек пришедший в проект, через 3 года (когда старых людей уже нет в команде) — просто ничего не поймет из доки и придется читать код. Есть еще важный момент — аналитики и менеджеры тоже должны знать что там есть и понимать это человеческим языком — иначе каждая их задача в итоге превратится в ежедневную «допилку» API и они не смогут экономить время разработки.
Два источника — совсем не так. Задача на разработку API в jira/redmine — ну никак не источник документации ее вообще потом могут не найти, да и искать не нужно. Источник один — где там удобно в wiki, в конфлюенс или где то еще.
Проблема в том, что документацию часто приходится дополнять, поправлять.
Если так приходится делать — вы либо теряете обратную совместимость, либо делаете новую версию, либо изначально сделали не то что хотели — это совсем не вопрос ведения документации, скорее вопрос к тому что вы делаете и зачем.
Как минимум описание «что? зачем? когда нельзя использовать? когда нужно?».
Конечно, именно о такой документации я и говорю. Держим в коде, экспортируем куда угодно при помощи всяких клёвых утилит, многократно упомянутых выше.
… Выложите новый метод на боевой сервер — просто скопируете документацию из задачи в ваше хранилище документации
… Задача на разработку API в jira/redmine — ну никак не источник документации ее вообще потом могут не найти, да и искать не нужно.
Вы начинаете путаться в показаниях.
Если так приходится делать — вы либо теряете обратную совместимость, либо делаете новую версию...
Стоп, я не говорил о BC breaking changes, я говорил лишь о доработке документации: забыли описать важную фичу, описали что-то недостаточно ясно, да просто орфографические и пунктуационные ошибки. Вы описываете какой-то идеальный кейс, когда ничего этого никогда не происходит.
забыли описать важную фичу, описали что-то недостаточно ясно, да просто орфографические и пунктуационные ошибки.
вот эти проблемы и решает мой подход. это не идеальный кейс, а нормаьный и достаточный.
Вы начинаете путаться в показаниях.
Не начинаю. Вы снова не поняли. В задаче есть «документация» — да. но ее там никто кроме разработчика читать не будет. читать ее будут в хранилище документации. вы часто ставите задачи? в теле задачи пишите что нужно сделать и доку. ок. задача готова и идет в топку т.к. никому не нужна. документация идет в хранилище. все проще, чем вы представляете. не усложняйте ;-)
А правильно логгировать — отдельное искусство. Для высоконагруженных серверов обычно применяют вот такие практики:
- Успешный запрос должен логгировать аккуратно выверенный минимум информации. Если объем реально большой, то логгировать нужно каждый n-ный запрос. Тогда в случае массовых ошибок в логах гарантированно окажутся нужные данные
- При высоких требованиях к latency используют не текстовые, а двоичные логи, опционально еще и сжимая их перед записью
- В наше время сеть куда быстрее диска, так что если нет жестких требований к целостности логов, можно логгировать их в сеть на специализированный сервис, типа Kafka
- Должна быть возможность включать debug-логгирование временно для всего приложения и для отдельных запросов, например, указывая специальный флаг в теле запроса
- Полезные метрики, типа кол-ва запросов в секунду, не считаются через анализ логов, а собираются и аггрегируются самим приложением и пишутся раз в n секунд.
- логи должны содержать requestId, уникальный для каждого запроса, желательно в пределах всей системы, а не только одного приложения.
- для бизнес-аналитики очень полезно иметь структурированные логи, например, в виде json, где назначение каждого поля описано в отдельном документе, и названия полей консистентны для всей системы.
Когда мы написали сотое API мы поняли…