Разработка интуитивно понятного и удобного RESTful API — непростая задача. Она даже может оказаться весьма сложной задачей, если это ваша первая попытка. Планирование управления жизненным циклом вашего API, скорее всего, будет казаться второстепенным. Однако во всяком случае развитие вашего API весьма вероятно.  Поэтому в этом посте я хотел бы предложить пошаговый подход к развитию ваших API, даже если это не было запланировано сразу. Давайте рассмотрим пример приложения, которое говорит «Hello» при его запуске. Базовая технология не имеет значения — мы сосредоточимся на API части. Первым и наиболее важным шагом является прекращение прямого доступа приложения к Интернету и установка шлюза API перед ним. Если вы не знакомы с концепцией API-шлюза, вы можете представлять его как мощный обратный прокси-сервере.  Википедия предлагает следующее определение: Gateway  (Шлюз): сервер, который работает как API интерфейс, получает запросы API, применяет политики регулирования и безопасности, передает запросы внутренней службе, а затем возвращает ответ запрашивающей стороне. Шлюз часто включает механизм преобразования для организации и изменения запросов и ответов на лету. Шлюз также может предоставлять такие функции, как сбор аналитических данных и кэширование. Шлюз может предоставлять функциональные возможности для поддержки аутентификации, авторизации, безопасности, аудита и соответствия нормативным требованиям. — API management   В этом посте я буду использовать Apache APISIX, но вы можете использовать тот, с которым вы лучше всего знакомы. Предоставление доступа к приложению через шлюз вместо непосредственного доступа требует, чтобы вы обновили записи DNS, чтобы они указывали на шлюз, а не на приложение, и подождите, пока они не будут распространены по всему миру. Это может занять некоторое время. Чтобы следить за распространением, вы можете использовать такой сайт, как dnschecker. Однако сначала вам нужно направить ваши HTTP-запросы от шлюза к вашему приложению. С APISIX вы можете создать маршрут, отправив HTTP-запрос на шлюз. APISIX может назначить автоматически сгенерированный идентификатор или использовать указанный вами. В нашем случае мы выбираем последнее и передаем его в URL-адресе 1 и используем глагол PUT Для обновления маршрутов нам нужно передать ключ API Именование маршрута не требуется, но позволяет нам лучше понять, что он делает Массив HTTP-методов для маршрутизации Массив URL для маршрутизации upstream — это внутреннее приложение. В нашем случае это Hello World API. Hashmap узлов с их соответствующим весом. Вес имеет смысл только при наличии нескольких узлов, что не так в нашем простом сценарии. Алгоритм балансировки для использования при настройке нескольких узлов На этом этапе вы можете запросить шлюз и получить те же результаты, что и раньше: Развитие API означает, что несколько версий API должны будут сосуществовать в какой-то момент. Существует три варианта реализации версии API: ТИП ПРИМЕР Параметр запроса curl http://org.apisix/hello?version=1curl http://org.apisix/hello?version=2 Заголовок curl -H 'Version: 1' http://org.apisix/hellocurl -H 'Version: 2' http://org.apisix/hello Путь curl http://org.apisix/v1/hellocurl http://org.apisix/v2/hello Много статей было написано о том, что является лучшим вариантом. В рамках этого поста мы будем использовать управление версиями на основе путей, поскольку он является наиболее распространенным. APISIX поддерживает другие варианты реализации, если вы хотите использовать их вместо этого. В предыдущем разделе мы создали маршрут, который обернул upstream. APISIX позволяет нам создать upstream с выделенным идентификатором, чтобы повторно использовать его в нескольких маршрутах. Используем путь upstreams Данные для нового upstream  Нам также нужно переписать запрос, который приводит к шлюзу, который перенаправит его в upstream. Последний знает /hello,  а не /v1/hello. APISIX позволяет выполнять такие преобразования, фильтры и т. д. с помощью плагинов. Давайте создадим конфигурацию плагина для преобразования пути: Используем путь plugin-configs Используем плагин proxy-rewrite Удаляем префикс версии Теперь мы можем создать версию маршрута, который ссылается на недавно созданную конфигурацию upstream и плагина: Вот вам новый маршрут! На этом этапе мы настроили два маршрута, один версионный, а другой неверсионный: Мы версионировали наш API, но наши пользователи, вероятно, все еще используют устаревший неверсионный API. Мы хотим, чтобы они мигрировали, но мы не можем просто удалить устаревший маршрут, поскольку наши пользователи не знают о том, что он устарел. К счастью, код состояния HTTP 301 — наш друг: мы можем сообщить пользователям, что ресурс переместился с http://org.apisix/hello на http://org.apisix/v1/hello. Для этого требуется настроить плагин перенаправления на исходном маршруте: Результаты интересны: Опция -L - принимать и обрабатывать перенаправления   Либо пользователи будут прозрачно использовать новую конечную точку, потому что они будут следовать по версионному пути, либо их запрос прервется, и они увидят статус 301 и описание нового местоположения API для использования. Вы могли заметить, что до сих пор мы понятия не имели, кто использует наш API. Когда нам нужно было внести изменение, мы должны были проявить творческий подход, чтобы не нарушать использование API пользователями. С другими изменениями может быть не так просто справиться. Следовательно, мы должны стремиться узнать наших пользователей, чтобы связаться с ними в случае необходимости. Давайте будем честными в этом; большинство разработчиков, в том числе и я, не любят регистрироваться и давать контактные данные, если можно этого избежать. Думаю, это вина маркетинговых команд, которые не понимают нашего мышления — не звони мне, я позвоню тебе. Но в данном конкретном случае это было бы полезным. «Ядерный» вариант полностью запрещает пользователям вызывать наш API до регистрации в системе. Я предпочитаю другой вариант: ограничить количество вызовов незарегистрированных пользователей в течение фиксированного периода времени. Если они достигнут предела, мы вернем HTTP статус 429 (неизвестный) и сообщение, предлагающее им зарегистрироваться. На момент написания этой статьи ни один готовый плагин не позволял этого добиться. Но можно написать свой. APISIX работает поверх движка Lua, и все предоставляемые плагины написаны на Lua. Кроме того, вы можете написать свои плагины на Go, Python, WebAssembly или любом другом языке на основе JVM. Для простоты я написал Lua плагин. Поскольку целью этого поста не является понимание Lua, я не буду углубляться в него. Если вам интересен код, он доступен на GitHub. Когда вы будете готовы, вам еще предстоит выполнить пару шагов: Настройте APISIX для использования определенного каталога: config.yaml Теперь APISIX может использовать любой скрипт Lua, расположенный в папке /opt/apisix/ Загрузите плагин: APISIX может выполнять горячую перезагрузку. Нам не нужно перезапускать его и ждать, чтобы добавить дополнительные плагины! Исправьте существующую конфигурацию плагина: Наконец, нам нужно настроить сам плагин. Поскольку мы создали специальную конфигурацию плагина, нам нужно только обновить его, чтобы использовать новую конфигурацией: К сожалению, нам нужно повторить имеющуюся конфигурацию плагина. Команда APISIX работает над исправлением, чтобы вы могли добавить плагин в конфиг, не зная существующего.   Наш плагин! Если пользователь не аутентифицирован, плагин ограничивает более одного звонка за 60 секунд. В остальном он ничем не ограничивается. Объяснение в следующем разделе   Теперь мы можем проверить, ведет ли он себя так, как ожидалось: Действительно, все так как ожидалось. Вероятно, вы должны видеть, как ваши пользователи посещают страницу регистрации, в зависимости от того, насколько вы ограничиваете использование без аутентификации. Регистрация имеет много аспектов, в частности: Автоматизированы или требуют столько шагов ручной проверки, сколько требуется Бесплатно или платно Просто, как запрос адреса электронной почты без дополнительной проверки, или сложно, как запрос значительно большего количества данных и т. п. Это зависит от вашего конкретного контекста. Что касается APISIX, в конце концов, это приводит к новому потребителю. Чтобы создать такого потребителя, нам нужно настроить плагин, который задает аутентификацию. Несколько плагинов аутентификации доступны из коробки: базовый, ключ API, JWT, OpenId, LDAP, Keycloak и т. д. В рамках этого поста достаточно плагина аутентификации по ключу. Давайте настроим объект-потребитель, который аутентифицируется с помощью ключа API: идентификатор потребителя Используемый плагин  Действительный токен mykey Обратите внимание, что заголовок по умолчанию — apikey. Можно настроить еще один: пожалуйста, ознакомьтесь с документацией плагина key-auth. Теперь мы можем протестировать нашу установку и убедиться, что она работает в соответствии с нашими требованиями: На этом этапе мы готовы сообщить пользователям об улучшенной версии нашего API Hello world. Я предполагаю, что наша команда тщательно протестировала его, но новый код — это всегда риск. Развертывание новой версии существующего приложения с ошибками может негативно сказаться на имидже поставщика API (и на доходах!). Чтобы свести к минимуму риски, общепринятая стратегия заключается в выпуске Canary release: Canary release — это метод снижения риска внедрения новой версии программного обеспечения в рабочую среду путем поэтапного развертывания изменения для небольшого подмножества пользователей, прежде чем оно будет распространено на всю инфраструктуру и станет доступным для всех. — CanaryRelease Если что-то выйдет из строя, это повлияет лишь на часть пользовательской базы, и мы сможем отменить изменение без особых последствий. Однако с помощью шлюза API мы можем ввести еще онин шаг перед Canary release: мы продублируем производственный трафик на новую конечную точку API. Несмотря на то что шлюз отклонит ответ, мы сможем обнаружить дополнительные ошибки без каких-либо последствий для пользователей. APISIX предлагает плагин прокси-зеркала для дублирования производственного трафика на другие узлы. Давайте обновим конфигурацию нашего плагина: APISIX также будет отправлять трафик на этот хост Мы можем отслеживать как новую, так и старую конечные точки, чтобы убедиться, что на  новой не возникает больше ошибок, чем на старой. Если нет, мы можем исправить ошибки и снова выполнить повторное развертывание, пока не добьемся одинакового поведения. Теперь мы готовы выпустить Canary release. Во-первых, мы создаем upstream, который указывает на новый API: Затем мы можем заменить плагин proxy-mirror на traffic-split: Отправляет 50% трафика на новый API для демонстрационных целей. В реальной жизни вы, вероятно, начнете с меньшего уровня или даже настроите только внутренних пользователей на новую конечную точку. Если все работает нормально, мы можем постепенно увеличивать процент трафика, отправляемого на новый API, пока не достигнем 100%. Теперь мы можем удалить разделение трафика и перенаправить с конечной точки по умолчанию на v2 вместо v1. Большинство пользователей, вероятно, перейдут на новую версию, чтобы воспользоваться ее преимуществами, но часть из них останется на v1. Для этого может быть множество причин: нет подходящего времени (подсказка: его никогда не бывает), слишком дорого, недостаточно стимулов для миграции, что угодно. Но для поставщика API каждая развернутая версия имеет определенную стоимость. В какой-то момент вам, вероятно, придется отказаться от v1. REST не является стандартом, но у IETF есть предварительная спецификация для него. Для получения более подробной информации, пожалуйста, прочитайте Поле Deprecation HTTP-заголовка. Как следует из названия, он основан на определенном заголовке HTTP ответа. С помощью шлюза API мы можем настроить маршрут, чтобы сообщать о его будущем устаревании и его замене. Для этого APISIX предлагает функцию response-rewrite. Хотя он может переписать любую часть ответа, мы будем использовать его для добавления дополнительных deprecation заголовков: В этом посте мы описали простой пошаговый процесс управления жизненным циклом ваших API: Не раскрывайте свои API напрямую; настройте API-шлюз перед ним Версионируйте существующий API, используя путь, параметр запроса или заголовок запроса. Мигрируйте пользователей с неверсионной конечной точки на версионную с помощью кода состояния 301. Мягко подталкивайте пользователей к регистрации Протестируйте API в рабочей среде, сначала продублировав трафик, а затем переведя небольшую часть пользователей на новую версию. Официальный выпуск новой версии Сообщите об устаревании старой версии через стандартные заголовки ответов. Полный исходный код для этого поста можно найти на Github в формате maven.