В этой статье подробно рассказывается, как можно объединить несколько схем отдельных служб OpenApi в глобальную схему, переназначив их маршруты, что упрощает поддержание всего вашего API в актуальном состоянии.
Первая часть этой статьи была хорошо принята, некоторые проблемы были решены и внесены улучшения. Мы хотели бы поблагодарить вас за отзывы и материалы. Мы с большим удовольствием публикуем вторую часть этой статьи, а также делимся с сообществом отличными новостями.
Новые функции, представленные в версии 1.0.0 ts-openapi, обновление с критическими изменениями:
- Методы теперь можно помечать как устаревшие
- Добавлена поддержка моделей данных
- Добавлена поддержка параметров
- Добавлена поддержка для объединения нескольких определений службы (см. последний раздел этой статьи).
Обновлена документация, а также обновлен пример сервера до этой версии. Единственное ограничение на данный момент заключается в том, что он работает только со схемами OpenApi 3.0.x. Пока swagger-ui-express или swagger-ui не поддерживает версии 3.1.x, обновляться не имеет особого смысла.
В этой статье мы рассмотрим четыре темы: первые две относительно просты, а последние сложны, но увлекательны. Мы объясним, как получить различные определения службы и использовать их для автоматического обновления вашего полного API. Для справки посмотрите демо-видео сервера смешивания в нижней части статьи.
Ниже приведен список тем, которые мы рассматриваем в этой статье:
Часть II:
- Создание проверочного промежуточного ПО, чтобы сделать ваши API надежными
- Автоматизация генерации документации
- Получение различных схем обслуживания
- Объединение нескольких схем OpenAPI для поддержания полной спецификации API в актуальном состоянии.
Шаг 1. Создание промежуточного ПО, чтобы сделать ваши API надежными
В контексте Express промежуточное ПО — это функция, используемая до и/или после дескриптора запроса, которая может стать мощной при использовании Joi в качестве средства очистки ввода. Однако важно не только убедиться, что все его параметры существуют и верны, но также проверить, содержит ли запрос какие-либо элементы, которые не были объявлены.
Например, представьте, что у нас есть определение тела и промежуточное ПО для его проверки. Затем представьте, что мы использовали оператор spread (…) для создания или обновления с помощью knex. Если вы думаете, что тело готово, подумайте еще раз! Joi по умолчанию позволяет передавать в тело неизвестные параметры. То есть его функция заключается только в проверке введенных нами параметров. Это означает, что даже если вы подтвердили наличие правильных параметров, другие параметры могут изменить столбцы базы данных, если они совпадают с именем столбца. Поэтому в некоторых случаях, например в случае с телом, очень важно убедиться, что Joi не допускает неизвестных в схеме.
Нам нужно проверить четыре разных ввода данных, каждый с разными правилами:
- Body: здесь безопасно иметь некоторый необязательный параметр, поскольку мы не должны разрешать неизвестные из соображений безопасности.
- Запрос. Вы можете разрешить неизвестные, но безопаснее просто заблокировать их. Параметры запроса являются необязательными.
- Параметры: неизвестные не допускаются, и все они обязательны, поскольку они являются частью URL-адреса, и мы не хотим никаких сюрпризов.
- Заголовки. Мы должны разрешить здесь неизвестные, так как мы не знаем заголовки, отправленные всеми браузерами. Обратите внимание, что имена заголовков должны быть в нижнем регистре, так как Express доставляет их внутри. Параметры заголовка являются необязательными.
С помощью этой настройки мы усилили проверку ввода и сделали наш API намного безопаснее. Вы можете использовать проверку файлов cookie, если используете файлы cookie. Имейте в виду, что ваше определение схемы для каждого источника данных должно соответствовать параметрам промежуточного ПО по умолчанию для обязательных и необязательных полей. Мы рекомендуем всегда помечать параметры как необязательные или обязательные.
Затем давайте создадим промежуточное ПО для каждой конечной точки, используя функцию, которая возвращает функцию проверки для каждой конечной точки в соответствии с вашим определением:
Мы использовали это промежуточное программное обеспечение на нашем демонстрационном сервере в разделах «список клиентов» и «создание клиента», если хотите взглянуть.
Шаг 2. Автоматизация создания документации
Затем выберите нужные вам инструменты. Одна из удивительных особенностей OpenApi — это широкий выбор доступных инструментов, таких как генераторы кода для разных языков, инструменты проверки, документация и т. д.
В этой демонстрации мы будем использовать widdershins.
Шаги для создания документации:
- установить виддершинс: npm i -g виддершинс
- Запустите локальный сервер: node ./src/server.js
- Создайте документацию вручную из URL-адреса сервера:
widdershins -c --summary “https://localhost:8000/api-json' -o api.md
Мы исключена генерация кода для получения простой текстовой документации, но есть множество различных опций, доступных на ваш выбор, таких как выбор языка и даже пользовательские шаблоны. - Вы также можете добавить его в package.json внутри скриптов:
"scripts": {
"documentation": "npx widdershins -c — summary
\"http:/ /localhost:8000/openapi.json\” -o api.md”
}, (…)
и вызовите его, запустив документацию по запуску npm.Только не забудьте сначала запустить свой сервер!
Следуя этим шагам, вы убедитесь, что ваша документация удобочитаема и всегда актуальна:
Шаг 3. Получение различных схем службы
До сих пор мы обсудили только одну службу и объяснили, как создать для нее схему OpenApi. Но что, если у вас есть сотни сервисов, каждый со своей схемой и документацией? Хуже того, что, если вы должны поддерживать общедоступную документацию в актуальном состоянии?
Кошмар для всех технических писателей
Как правило, большие API имеют не одну службу, которая их реализует, а сотни служб, работающих вместе для создания полноценного API, каждая из которых имеет несколько или сотни экземпляров, в зависимости от количества запросов или даже их сложности.
Что стоит за этим «волшебством»? Ответ — балансировщики нагрузки или какие-то обратные прокси, такие как Nginx, Traefik, HAProxy, Perlbal и, для тех, кто может себе это позволить, аппаратно оптимизированные ssl-ускорители.
Эти балансировщики нагрузки обычно имеют дело со слоем HTTPS и доставляют трафик HTTP во внутреннюю сеть. Точнее, службе, которая его обрабатывает (при условии, что это безопасно). Таким образом, внутренние службы обрабатывают регулярный незашифрованный трафик в своем центре обработки данных, который легко обработать и отправить ответ балансировщику нагрузки для шифрования обратно в браузер клиента.
Предположим, мы хотим реализовать «Awesome API Explorer» с тремя службами: пользователями, продуктами и электронной почтой.
В этом случае запросы к https://awesome.api/users/* необходимо будет перенаправлять пользователям внутренней службы https://users/public. /* . Это означает, что всякий раз, когда запрос соответствует /users/*, балансировщик нагрузки переписывает путь запроса на /public/* и передает его экземпляру этой службы для обработки. Далее предположим, что эта схема службы доступна по адресу https://users/private/openapi.json.
https://awesome.api/products/* запросы будут направляться в службу products https://products/*, а схема будет доступна по адресу https://products /openapi.json
https://awesome.api/emails/* запросы будут направляться в службу emails https://emails/api/*, а схема будет доступна по адресу http:/ /emails/api-schema.json
Итак, из приведенных выше определений службы мы выделяем три компонента: общедоступный путь, частный путь и расположение схемы (используется для обновлений).
Одно важное примечание о безопасности: некоторые службы имеют как частные, так и общедоступные API. В этом случае вы должны создать свой API таким образом, чтобы он не подвергался рискам. Если вы не объявляете свои методы публично, это не снижает риска, потому что до тех пор, пока они доступны, их также можно взломать.
Мы рекомендуем хранить схемы служб в секрете, поскольку они могут выдать информацию о вашей инфраструктуре служб хакерам.
Короче говоря, нам нужно получить три схемы по указанным ниже адресам, преобразовать пути из частных в общедоступные, а затем объявить новые адреса общедоступных серверов:
https://users/private/openapi.json, сопоставьте пути от /public/*до /users/*
https://products/openapi. json, сопоставление путей из /* в /products/*
https://email/api-schema.json, сопоставление путей из /api /*в /emails/*
Получение нескольких схем с разных URL-адресов тривиально. Самый важный шаг – создание собственных правил и системы обновлений. Если вам нужно немедленно обновить схему API, мы рекомендуем механизм триггера, например очередь или веб-перехватчик, который получает событие обновления, считывает новую схему из определенной службы, а затем создает новый комбинированный API. В противном случае вы можете обновлять свой API через равные промежутки времени, каждую минуту или час, в зависимости от ваших потребностей. Если во время смешивания сервисов возникает ошибка, обязательно зарегистрируйте ее, но оставьте предыдущее определение комбинированного сервиса активным на всякий случай и до тех пор, пока ошибка не будет исправлена.
Далее давайте создадим список с нашими конфигурациями сервисов:
const services = { "users": { schemaUrl: "https://127.0.0.1:2000/private/openapi.json", publicPrefix: "/users/", privatePrefix: "/public/", type: "consul" }, "products": { schemaUrl: "https://127.0.0.1:3000/openapi.json", publicPrefix: "/products/”, privatePrefix: "/", type: "static" }, "emails": { schemaUrl: "https://127.0.0.1:4000/api-schema.json", publicPrefix: "/emails/", privatePrefix: "/api/", type: "consul" } }
С помощью этого списка мы можем собрать каждое отдельное определение и объединить их для создания глобального определения. Обратите внимание, что мы присвоили каждому определению свой тип. Причина в том, что у сервисов на основе консула может быть изменен их IP/порт, поэтому перед их получением мы всегда должны обновлять их адрес/порт. Возможно, вам придется сделать то же самое с другими системами обнаружения служб.
Наш общедоступный API будет обновляться с нашим сервером mingle, полная демонстрация доступна по адресу https://github.com/nelsongomes/server/tree/main/src/mingle-demo.ts :
const app: Application = express(); // read initial schema let currentSchema = await getMingledApi(); // creates an endpoint to reply with openapi schema app.get('/api/openapi.json', function (_req, res) { res.setHeader("Cache-Control", "no-store, must-revalidate"); res.setHeader("Expires", "0"); res.json(currentSchema); }); const options = { swaggerOptions: { url: '/api/openapi.json', }, }; // this will make openapi UI available with our definition app.use("/api", swaggerUi.serveFiles(undefined, options), swaggerUi.setup(undefined, options) ); // try to refresh schema every X seconds setInterval(async () => { try { currentSchema = await getMingledApi(); } catch (e) { // log any errors during service mingle attempt plus failed attempts should // not crash server because we keep state from latest attempt console.log(e); } }, REFRESH_SECONDS * 1000); // start server app.listen(PORT, function () { console.log(`Server is listening on port ${PORT}! Click https://127.0.0.1:${PORT}/api/`); });
Этот сервер сделает наш публичный API-интерфейс доступным по адресу https://127.0.0.1:8888/api/, а нашу схему API — по адресу https://127.0.0.1:8888/api/openapi.json и попытается обновить свою схему. каждую минуту.
Шаг 4. Объединение нескольких схем OpenAPI для поддержания полной спецификации API в актуальном состоянии
Объединение нескольких схем сервисов — непростая задача для разработчиков. Вам нужно:
- Фильтровать частные маршруты (недоступные извне)
- Убедитесь, что идентификаторы операций уникальны для всех служб.
- Переназначить частные пути на общедоступные пути
- Проверьте, есть ли ссылки на схемы (в теле и в каждом из возможных кодов ответа), и скопируйте их.
- Проверьте, имеет ли схема, объявленная несколькими службами, одинаковое значение (мы должны избегать общих схем, когда это возможно, чтобы избежать конфликтов)
- Проверьте, ссылается ли ссылка на схему внутри других схем, и скопируйте их тоже.
- Проверьте, ссылаются ли на параметры, и скопируйте их.
- Проверить, соответствуют ли схемы безопасности декларации
- Проверяйте локальные схемы безопасности (уровень методов) на заявленные и проверяйте области действия.
Примечание о моделях. Мы рекомендуем определять схемы, управляемые доменом, чтобы только одна служба имела все методы для обработки продуктов и могла объявить для нее модель. Если у вас есть несколько сервисов, объявляющих одну и ту же модель, вы можете столкнуться с конфликтующими моделями. Поэтому, чтобы избежать множественных определений Product, все службы, которым требуются данные Product, должны вызывать для них одну и ту же службу.
Чтобы протестировать сервер смешивания, загрузите код с https://github.com/nelsongomes/server. Измените файл src/mingle-demo.ts, чтобы добавить свою конфигурацию, и запустите его, выполнив ts-node src/mingle-demo.ts .
Чтобы проиллюстрировать эту статью, мы создали несколько реплик нашего демо-сервиса с вышеупомянутыми конфигурациями, некоторыми схемами безопасности, некоторыми моделями и свойствами. Вы также можете получить доступ к пользовательскому интерфейсу смешивающего сервера по адресу https://127.0.0.1:8888/api/.
Чтобы проверить вашу схему, мы рекомендуем следующий инструмент: https://editor.swagger.io/, просто скопируйте вашу схему JSON в инструмент, и он укажет на любые проблемы со схемой, которые могут у вас возникнуть.
Чтобы поддержать настройку, не забудьте правильно настроить балансировщик нагрузки, выполнив маршрутизацию:
- /api/ для объединения серверов
- /users/ в службу пользователей
- /продукты/ для обслуживания пользователей
- /emails/ в службу электронной почты
Наконец, учитывая, что теперь у нас есть способ обеспечить постоянное обновление нашего общедоступного API, мы можем легко автоматизировать документацию для него с помощью widdershins, как описано в шаге 2.
Этот проект был создан, чтобы помочь нам использовать комбинированные распределенные схемы для больших API. Поскольку он становится все более амбициозным, вы можете найти некоторые ошибки и проблемы в нашем рабочем процессе. Если это так, пожалуйста, поделитесь с нами своим опытом. Мы надеемся, что вы правильно воспользуетесь информацией, упомянутой в этой статье, и хотели бы поблагодарить вас за чтение.
Соответствующие ссылки:
- https://github.com/nelsongomes/server (демонстрационный сервер);
- https://github.com/nelsongomes/server/blob/main/src/mingle-demo.ts (демонстрация сервера mingle);
- https://www.npmjs.com/package/ts-openapi (ссылка на пакет);
Другие ресурсы, использованные в этой статье:
- https://pixabay.com/illustrations/digitization-transformation-binary-5140071/
- https://www.youtube.com/watch?v=gCJ0uRMgd0A
- https://wideo.co/текст-в-речь/
Хотите работать в Pipedrive?
В настоящее время мы набираем сотрудников на несколько разных должностей в разных странах/городах.
Посмотрите и посмотрите, подходит ли вам что-то
Позиции включают в себя:
- Младший разработчик
- Полный стек разработчик
- Ведущий инженер
- Младший инженер-программист в DevOps Tooling
- Старший разработчик интерфейса
- Инженер по инфраструктуре
- И еще несколько