Pull to refresh

Comments 41

UFO just landed and posted this here
Это я и есть. Такие эксперименты приносят хорошие деньги — можно и оплачивать.
Ахах) Напомнило: «Вы думаете, господа, что государство — это вы? Вы ошибаетесь, господа, государство — это я!» (Людовик XIV).
Жаль, что не рассказали относительно того, как именно вы версионируете API на уровне кода.
Под каждую версию API держите свою ветку?
Или поддерживаете все версии внутри одной кодовой базы?
Новое API — новый микросервис, у нас SOA
Т.е. новый репозиторий? А что происходит, если нужно поднять минорную версию? Например с 1.0 до 1.2. Или накатить фикс сразу на две мажорные: 1.2 -> 1.2, 2.0 -> 2.1.
В понятиях микросервисов и нашем подходе — минорная версия это багфикс. Он обязан быть обратносовместим и сохранять интерфейс.
После появления новой версии, старая снимается с поддержки даже с багфиксрв.

Обычно у нас версия 1 — это рабочий прототип на php, а 2ая это полноценная версия на C++. Далее изменения уже не требуются.

Ну и читайте статью — https://megamozg.ru/post/24718/, там все ответы
«Никогда не верьте в то что Вы изобрели способ версирования API» — долгие годы ждал, когда эту правду скажут вслух.
Надо будет статью полную такой правды в виде тезисов написать

Добавлю также от себя:


  • Все методы, изменяющие состояние, будь то в БД или in-memory, должны быть как минимум POST, или же детализироваться — PUT/DELETE
  • Есть критические бизнес-функции, требующие не только некоего входного набора параметров — но и, скажем некоей проверочной контрольной суммы на ключевые поля добавляемой сущности. Скажем так, checksum token в таких методах — это очередная линия обороны против плохо составленных запросов.
  • Отдельные части location'а должны быть как можно более краткими. Скажем, для случая если вы запрашиваете информацию по товару — /products/get/{id}, а не /get-product/{id}

Большая часть советов по обходу граблей REST API была описана еще в статье от Яндекса
https://habrahabr.ru/company/yandex/blog/265569/

Отдельные части location'а должны быть как можно более краткими. Скажем, для случая если вы запрашиваете информацию по товару — /products/get/{id}, а не /get-product/{id}

Я бы предложил GET /products/{id}
Мне нравится как организован REST-модуль в Yii2. Все элементарно просто и при этом функционально и соответствует стандартам и лучшим практикам. Советую посмотреть их документацию и полистать исходники, наверняка что-то новое для себя откроете: https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/rest-quick-start.md

Я даже делал клиентсткую REST-библиотеку для Qt (доступен здесь https://github.com/kafeg/qtrest), которая основана на философии Yii2 REST API.

Как там реализовано версионирование?

В рамках проекта API создается модуль по названию версии v1, v2, etc…
В каждом модуле — набор контроллеров, которые используют единый набор моделей данных.

При создании новой версии API — наследуем все контроллеры от контроллеров предыдущей версии, внося необходимые изменения в каждый новый контроллер.

Таким образом, поддержка в работоспособном виде всех версий заключается в правке нужного контроллера в последней или одной из промежуточных версий API.

Например: https://github.com/githubjeka/yii2-rest/blob/master/rest/versions/v2/controllers/PostController.php

Это делается автоматом, или надо делать руками? Что делать, если я не хочу, чтобы у разных версий были одинаковые DTO?

1. Наследование руками, но можно набросать пару скриптов.
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 нет — или я не нашел по вашему описанию — никакой реализации версионирования.

Так и есть. Разработчику предлагается сделать то, что вы описали в своем комментарии, используя стандартные концепции — то есть модуль вместо версии.

Валидация состояния модели и валидация http запроса — разные валидации. Совпадать они могут разве что в примитивных CRUD приложениях.
Насчет документации — мы пошли другим путем. Документация содержится непосредственно в коде, реализующем методы REST API. У нас Scala, это несколько улучшает внешний вид метаданных и уменьшает избыточность. При старте приложения по этим метаданным генерится HTML и вывешивается на /api в каждом микросервисе. Таким образом:
— документация всегда актуальна
— документация всегда под рукой (если ты можешь обращаться к микросервису, ты можешь сделать GET /api в браузере)
— и, в результате, мнгновенный ответ на вопросы типа «а что вообще умеет эта штука, которую мы два года назад написали?» и «подзабыл название поля в API, как быстро посмотреть»
Если в вашем случае это удобно — то супер. Я больше про общий случай — у нас php и C++
Ну т.е. для себя мы сделали переносимый метод не зависящий от инструментов
Используете что-то стандартное или свое? Можно ссылку или простой пример кода метода с документацией (настоящий текст можно заменить на что-то обезличенное)?
Спасибо!

Мы начинали со 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 })
UFO just landed and posted this here
Документация почти всегда не актуальна, а инструменты вроде swagger все равно требуют поддержки.

Вот тут можно чуть подробнее? О какой именно поддержке Сваггера вы говорите?

Как минимум написать 3 буквы в разметке. Это тоже поддержка. И дело не в том сколько букв, а в том что работают Люди — и мы все время от времени забываем их поправить.
А решение с постановкой задачи в виде доки — исключает любые факторы и не завязано на инструменты.

Нет, подождите. Я не знаю, о какой разметке вы говорите (у нас, например, это просто часть апи: нельзя выкатить незадокументированный метод), но дело даже не в этом. В любом случае же нужны какие-то усилия на документирование. И если я правильно понял (а я не исключаю, что понял неправильно), то вы предлагаете копировать документацию из одного места в другое («Выложите новый метод на боевой сервер — просто скопируете документацию из задачи в ваше хранилище документации.»). И теперь у вас два источника одной информации. Проблема в том, что документацию часто приходится дополнять, поправлять. Теперь на каждую правку нужно делать ещё и копирование, о котором забыть гораздо проще.


В целом то, что вы описываете, больше похоже на «сначала досканально спроектируйте метод апи, включая техническое проектирование, а затем — реализуйте». То есть, на этапе проектирования вы уже его документируете. Это всё правильно, да. Но что мешает затем документацию закрепить за методом и не копипастить повсюду? Сваггер и ему подобные инструменты как раз позволяют это сделать.

Видимо вы поняли частично правильно.

Документация к методу API — это же не только его название и набор параметров. Как минимум описание «что? зачем? когда нельзя использовать? когда нужно?». Ведь иначе новый человек пришедший в проект, через 3 года (когда старых людей уже нет в команде) — просто ничего не поймет из доки и придется читать код. Есть еще важный момент — аналитики и менеджеры тоже должны знать что там есть и понимать это человеческим языком — иначе каждая их задача в итоге превратится в ежедневную «допилку» API и они не смогут экономить время разработки.

Два источника — совсем не так. Задача на разработку API в jira/redmine — ну никак не источник документации ее вообще потом могут не найти, да и искать не нужно. Источник один — где там удобно в wiki, в конфлюенс или где то еще.

Проблема в том, что документацию часто приходится дополнять, поправлять.

Если так приходится делать — вы либо теряете обратную совместимость, либо делаете новую версию, либо изначально сделали не то что хотели — это совсем не вопрос ведения документации, скорее вопрос к тому что вы делаете и зачем.
Как минимум описание «что? зачем? когда нельзя использовать? когда нужно?».

Конечно, именно о такой документации я и говорю. Держим в коде, экспортируем куда угодно при помощи всяких клёвых утилит, многократно упомянутых выше.


… Выложите новый метод на боевой сервер — просто скопируете документацию из задачи в ваше хранилище документации
… Задача на разработку API в jira/redmine — ну никак не источник документации ее вообще потом могут не найти, да и искать не нужно.

Вы начинаете путаться в показаниях.


Если так приходится делать — вы либо теряете обратную совместимость, либо делаете новую версию...

Стоп, я не говорил о BC breaking changes, я говорил лишь о доработке документации: забыли описать важную фичу, описали что-то недостаточно ясно, да просто орфографические и пунктуационные ошибки. Вы описываете какой-то идеальный кейс, когда ничего этого никогда не происходит.

забыли описать важную фичу, описали что-то недостаточно ясно, да просто орфографические и пунктуационные ошибки.


вот эти проблемы и решает мой подход. это не идеальный кейс, а нормаьный и достаточный.

Вы начинаете путаться в показаниях.

Не начинаю. Вы снова не поняли. В задаче есть «документация» — да. но ее там никто кроме разработчика читать не будет. читать ее будут в хранилище документации. вы часто ставите задачи? в теле задачи пишите что нужно сделать и доку. ок. задача готова и идет в топку т.к. никому не нужна. документация идет в хранилище. все проще, чем вы представляете. не усложняйте ;-)
На мой взгляд, данной «статье» место в твитере. Вопрос API ну совсем не раскрыт… demo версия что ли?
Это был сарказм, на тему объёма статьи, ибо в тв ограничение на длину сообщения.
Я не против данной публикации, вы многое написали правильно, но еще больше упустили.
UFO just landed and posted this here
Террабайты не нужны — логротейт же. А от io спасает буферизация.
А анализировать удобно — zgrep, grep, cut, и всяким таким, если случай не особо тяжелый.

А правильно логгировать — отдельное искусство. Для высоконагруженных серверов обычно применяют вот такие практики:


  • Успешный запрос должен логгировать аккуратно выверенный минимум информации. Если объем реально большой, то логгировать нужно каждый n-ный запрос. Тогда в случае массовых ошибок в логах гарантированно окажутся нужные данные
  • При высоких требованиях к latency используют не текстовые, а двоичные логи, опционально еще и сжимая их перед записью
  • В наше время сеть куда быстрее диска, так что если нет жестких требований к целостности логов, можно логгировать их в сеть на специализированный сервис, типа Kafka
  • Должна быть возможность включать debug-логгирование временно для всего приложения и для отдельных запросов, например, указывая специальный флаг в теле запроса
  • Полезные метрики, типа кол-ва запросов в секунду, не считаются через анализ логов, а собираются и аггрегируются самим приложением и пишутся раз в n секунд.
  • логи должны содержать requestId, уникальный для каждого запроса, желательно в пределах всей системы, а не только одного приложения.
  • для бизнес-аналитики очень полезно иметь структурированные логи, например, в виде json, где назначение каждого поля описано в отдельном документе, и названия полей консистентны для всей системы.
Sign up to leave a comment.

Articles