├── .gitignore ├── .gitlab-ci.yml ├── README.md ├── api-process.md ├── concepts ├── definitions.md └── team-maturity.md ├── examples └── README.md ├── getting-started └── README.md ├── img ├── .gitignore ├── api-process.png ├── logo.png └── src │ ├── api-first-process.drawio │ └── api-process.drawio ├── practices └── README.md ├── publishing └── README.md ├── rules ├── CONTRIBUTING.md ├── rule-format.md ├── rules-process.md ├── rules-structure.md └── rules.md ├── tools └── README.md └── use-cases └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - deploy 3 | 4 | variables: 5 | APP_NAME: rest-api-guide 6 | VERSION: 1.1.$CI_PIPELINE_IID 7 | 8 | push: 9 | stage: deploy 10 | script: 11 | - git config --global user.email $OPEN_SOURCE_GITHUB_EMAIL 12 | - git config --global user.name $OPEN_SOURCE_GITHUB_LOGIN 13 | - git config --global http.https://github.com.proxy http://sys-proxy.raiffeisen.ru:8080 14 | - git config --global http.https://github.com.sslVerify true 15 | - git push https://$OPEN_SOURCE_GITHUB_LOGIN:$OPEN_SOURCE_GITHUB_TOKEN@github.com/Raiffeisen-DGTL/$APP_NAME.git HEAD:main --force 16 | only: 17 | - master 18 | image: artifactory.raiffeisen.ru/pos-acquiring-docker/cli-tools:latest -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 | Logo 7 | 8 | 9 |

API First Guide

10 | 11 |

12 | Единая точка входа к информации по процессу разработки API в банке 13 |
14 |

15 |
16 |
17 | 18 | - [🚀 Быстрый старт](#-быстрый-старт) 19 | - [С чего начать?](#с-чего-начать) 20 | - [📚 Структура руководства](#-структура-руководства) 21 | - [1. Getting Started](#1-getting-started) 22 | - [2. Практики API First](#2-практики-api-first) 23 | - [3. API Guide](#3-api-guide) 24 | - [4. Инструменты](#4-инструменты) 25 | - [5. Публикация API](#5-публикация-api) 26 | - [6. Use Cases](#6-use-cases) 27 | - [7. Примеры реализации](#7-примеры-реализации) 28 | 29 | 30 | ## 🚀 Быстрый старт 31 | 32 | ### С чего начать? 33 | 1. **[Изучите Getting Started Guide](getting-started/README.md)** - пошаговое руководство для команд 34 | 2. **[Примените практики](practices/README.md)** API First в вашей команде 35 | 3. **[Выберите инструменты](tools/README.md)** для вашего стека технологий 36 | 4. **[Следуйте API Guide](rules/rules.md)** для соблюдения стандартов банка 37 | 38 | ## 📚 Структура руководства 39 | 40 | ### 1. [Getting Started](getting-started/README.md) 41 | Пошаговое руководство для команд, которые хотят начать работать по API First: 42 | - Что такое API First и зачем он нужен 43 | - Чеклист готовности команды 44 | - Roadmap внедрения API First 45 | - Частые вопросы и решения 46 | 47 | ### 2. [Практики API First](practices/README.md) 48 | - Совместное создание контрактов (Contract First Design) 49 | - Хранение спецификаций (моно-репозиторий vs микросервисы) 50 | - API Review процесс 51 | 52 | ### 3. [API Guide](rules/rules.md) 53 | Стандарты и правила разработки API в банке: 54 | - Принципы проектирования REST API 55 | - Человекочитаемые правила 56 | - OpenSource процесс внесения изменений 57 | 58 | ### 4. [Инструменты](tools/README.md) 59 | Готовые инструменты для работы по API First: 60 | - **Редакторы спецификаций** 61 | - **Кодогенерация** 62 | - **Mock-серверы** 63 | - **Тестирование** 64 | - **Валидация** 65 | - **Документация** 66 | 67 | ### 5. [Публикация API](publishing/README.md) 68 | Как опубликовать ваше API: 69 | - **Внутренний портал** 70 | - **Внешний портал** 71 | 72 | ### 6. [Use Cases](use-cases/README.md) 73 | Руководства для специфических типов API: 74 | - Файловое API (upload/download) 75 | - Асинхронное API (async tasks, webhooks) 76 | - Batch операции 77 | - GraphQL в банке 78 | - Event-driven API 79 | 80 | ### 7. [Примеры реализации](examples/README.md) 81 | Реальные кейсы команд банка -------------------------------------------------------------------------------- /api-process.md: -------------------------------------------------------------------------------- 1 | 2 | ![Diagram](img/api-process.png) 3 | [Source](img/src/api-process.drawio) 4 | -------------------------------------------------------------------------------- /concepts/definitions.md: -------------------------------------------------------------------------------- 1 | # Концепции и определения 2 | 3 | - [Концепции и определения](#концепции-и-определения) 4 | - [Embedded Finance](#embedded-finance) 5 | - [API as a Product](#api-as-a-product) 6 | - [Ключевые принципы:](#ключевые-принципы) 7 | - [API First](#api-first) 8 | - [Ключевые принципы:](#ключевые-принципы-1) 9 | - [API First vs Code First](#api-first-vs-code-first) 10 | - [Code First](#code-first) 11 | - [API First](#api-first-1) 12 | - [Уровни API](#уровни-api) 13 | - [1. Внутрикомандное API / Internal API](#1-внутрикомандное-api--internal-api) 14 | - [2. Внутреннее API / Private API](#2-внутреннее-api--private-api) 15 | - [3. Клиентское API / Public API](#3-клиентское-api--public-api) 16 | - [4. Отраслевое API / Industry API](#4-отраслевое-api--industry-api) 17 | - [Протоколы](#протоколы) 18 | - [REST API (по умолчанию)](#rest-api-по-умолчанию) 19 | - [Асинхронные протоколы](#асинхронные-протоколы) 20 | - [Другие протоколы](#другие-протоколы) 21 | 22 | 23 | 24 | ## Embedded Finance 25 | Embedded Finance - это интеграция финансовых услуг непосредственно в продукты и услуги бизнеса через API. Это позволяет как финансовым, так и нефинансовым предприятиям предлагать такие услуги, как платежи, кредитование и страхование, не подвергаясь регулированию в качестве финансовых организаций и не создавая самостоятельно какую-либо финансовую инфраструктуру. 26 | 27 | Для нашего банка в целом и для CIB в частности это является стратегической целью, так как позволяет привлекать клиентов с большими транзакционными потребностями, а также удерживать клиентов. 28 | 29 | ## API as a Product 30 | Концепция, рассматривающая API как самостоятельный продукт или канал привлечения с целевой аудиторией и бизнес-сценариями. 31 | 32 | ### Ключевые принципы: 33 | - Бизнес ревью API на начальном этапе для любых разрабатываемых интерфейсных возможностей. Ключевой вопрос: как этот сценарий может быть полезным клиенту или другим продуктам в банке при подключении по API 34 | - Обсуждение с клиентами/интеграторами после прохождения бизнес-ревью 35 | - Создание тестовой среды до полноценной разработки сервиса 36 | - Продажа клиентам интеграции на базе тестовой среды 37 | - Доработка сервиса до полноценной реализации параллельно с продажей сервиса клиентам 38 | 39 | ## API First 40 | Подход к разработке программного обеспечения, приоритизирующий разработку и дизайн API в начало цикла разработки, до реализации других компонентов системы (например, пользовательского интерфейса). 41 | 42 | ### Ключевые принципы: 43 | - Проектирование API до разработки 44 | - Хранение API в формате, удобном для чтения человеком и машиной, в системе контроля версий 45 | - Спецификация API является единственным источником достоверной информации для документации 46 | - UI должен быть создан исключительно на основе общедоступного (внутри банка) API 47 | - Любой API может быть выдан смежным командам или клиентам без значительных временных затрат 48 | - Доступная для интеграции тестовая среда 49 | - Фокус на выполнение рекомендаций разработки 50 | 51 | ## API First vs Code First 52 | 53 | ### Code First 54 | Традиционный подход, при котором: 55 | - Сначала пишется код реализации 56 | - API документация создается после или во время разработки 57 | - Изменения в API требуют изменения кода и документации 58 | - Высокий риск расхождения документации и реальной реализации 59 | 60 | ### API First 61 | Современный подход, при котором: 62 | - Сначала проектируется и документируется API 63 | - Код создается/генерируется на основе спецификации 64 | - Документация всегда актуальна 65 | - Frontend и Backend могут разрабатываться параллельно 66 | - Изменения начинаются с обновления спецификации 67 | 68 | ## Уровни API 69 | 70 | ### 1. Внутрикомандное API / Internal API 71 | API, используемое для межсервисного взаимодействия внутри команды, к которому нет внешнего доступа, либо доступ появляется при непосредственной поддержке команды, написавшей его. 72 | 73 | **Ключевые признаки:** 74 | - Отсутствие открытой документации, примеров использования запросов, тестовой среды 75 | - Нет понятного способа получить ключи авторизации 76 | - Нестабильная работа тестового контура при его наличии 77 | 78 | **Контекст:** 79 | Большая часть API сейчас внутрикомандные. Цель - чтобы они все стали внутренними. 80 | 81 | ### 2. Внутреннее API / Private API 82 | API, документация и тестовая среда которого доступны для других команд в банке. 83 | 84 | **Ключевые ожидания:** 85 | - Открытая общебанковская документация со сценариями использования и примерами запросов 86 | - Стабильная и актуальная тестовая среда 87 | - Понятный способ получения ключей доступа для команд внутри банка (email в поддержку, email в команду, интерфейсные решения) 88 | 89 | **Контекст:** 90 | Вывод внутреннего API наружу сейчас нетривиальная процедура для большинства продуктов. Цель - упростить и стандартизировать, сделав это нормой. 91 | 92 | ### 3. Клиентское API / Public API 93 | API, документация и тестовая среда которого доступны для клиентов банка. 94 | 95 | **Ключевые ожидания:** 96 | - Открытая для клиентов документация с примерами, обязательно со сценариями использования 97 | - Стабильная и актуальная тестовая среда 98 | - Понятный способ получения ключей доступа (интерфейс в RBO/другом ЛК, email в поддержку) 99 | 100 | ### 4. Отраслевое API / Industry API 101 | API, разработанное на основе определенного стандарта или рыночной практики для конкретного сегмента клиентов. 102 | 103 | **Примеры:** 104 | - Интеграции 1C 105 | - ISO в DBLM 106 | - Агентское API в СБП у НСПК 107 | 108 | **Ключевые ожидания:** 109 | - Разработка на основе внутреннего или клиентского API через сервис-адаптер/конвертер запросов 110 | 111 | ## Протоколы 112 | 113 | ### REST API (по умолчанию) 114 | По умолчанию в банке выбран HTTP REST API для синхронного взаимодействия. 115 | 116 | ### Асинхронные протоколы 117 | Если того требует решение, то для внутренних сервисов может использоваться: 118 | - Kafka 119 | - MQTT 120 | - AMQP/RabbitMQ 121 | 122 | Для асинхронного взаимодействия для описания спецификации может быть использовано: 123 | - [AsyncAPI](https://www.asyncapi.com/) 124 | 125 | ### Другие протоколы 126 | - **gRPC** - [API First by design](https://protobuf.dev/) 127 | - **GraphQL** - для сложных запросов с вложенными данными 128 | - **SOAP/WSDL** - legacy системы 129 | 130 | > 💡 Независимо от выбора протокола стоит применять основные принципы API First. 131 | -------------------------------------------------------------------------------- /concepts/team-maturity.md: -------------------------------------------------------------------------------- 1 | # Критерии команды следующей практикам 2 | 3 | - [ ] [Спецификация АПИ появляется и сохраняется перед реализацией](#спецификация-апи-появляется-и-сохраняется-перед-реализацией) 4 | - [ ] [Совпадение контракта и реализации контролируется автоматически](#совпадение-контракта-и-реализации-контролируется-автоматически) 5 | - [ ] [Апи соответствует гайду с принятыми в сообществе правилами](#апи-соответствует-гайду-с-принятыми-в-сообществе-правилами) 6 | - [ ] [Апи проверяется на соответствие правилам автоматически](#апи-проверяется-на-соответствие-правилам-автоматически) 7 | - [ ] [Апи проходит кросскомандное ревью](#апи-проходит-кросскомандное-ревью) 8 | - [ ] [Апи опубликовано в общебанковском месте (Backstage)](#апи-опубликовано-в-общебанковском-месте) 9 | - [ ] [Апи опубликовано в человекочитаемом для клиентов (внешних по отношению к банку клиентов) виде (Redoc)](#апи-опубликовано-в-человекочитаемом-для-клиентов-внешних-по-отношению-к-банку-клиентов-виде) 10 | 11 | 12 | ## Спецификация АПИ появляется и сохраняется перед реализацией 13 | > Разработка в команде начинается с разработки спецификации API, спецификация API находится в gitlab в формате OpenAPI, AsyncAPI (или другом в соответствии с используемым протоколом). 14 | Изменения в API делаются с использованием Merge Request, финальное API приложено как артифакт к задаче. 15 | 16 | Перед реализацией правильнее будет видеть финальный контракт для того чтобы его можно было отдать в тестирование/фронтенд/другой сервис и тд. Контракт должен быть описан на универсальном языке понятном всем участникам процесса разработки не зависимо от роли и языка программирования. Предлагаемый контракт создается прежде всего исходя из бизнес-сценария. 17 | 18 | 19 | ## Совпадение контракта и реализации контролируется автоматически 20 | > Возможны 2 варианта контроля которые не исключают совместное использование: 21 | > - Настроена кодогенерация по спецификации, сгенерированный код используется проектом-реализацией. Таким образом несответствия спецификации и реализаци будут выявлены на раннем этапе сборки проекта. 22 | > - Настроено тестирование по спецификации. Соответствие обеспечивается на более позднем этапе, но могут проверятся более сложные условия в контракте. 23 | 24 | То апи которое описано и согласовано должно совпадать с реализацией. 25 | Контроль в ручную как правило рано или поздно приводит к расхождениям, соответственно необходимо обеспечить это автоматизированными средствами, это может бы кодогенерация или автоматическое тестирование контракта в соответствии с описанием. 26 | 27 | # Апи соответствует гайду с принятыми в сообществе правилами. 28 | > Апи построено в соответствии с договоренностями принятыми в [документе](rest-api-guide.md) 29 | 30 | Мы хотим чтобы наше апи строилось по понятным правилам для наших партнеров, смежных команд, а так же коллег внутри команды. 31 | 32 | # Апи проверяется на соответствие правилам автоматически 33 | > В пайплайне репозитория Gitlab где хранится API встроен автоматический запуск линтеров которые автоматически подсвечивают несоответствие API принятым правилам. Должны быть автоматизированы те проверки для которых это возможно сделать 34 | 35 | Выполнение соответствия АПИ гайду принятому в сообществе проверяется с помощью линтеров и валидаторов. 36 | 37 | # Апи проходит кросскомандное и бизнес ревью 38 | > В команде организован процесс, в котором соседние команды и представители от бизнеса могут провести ревью API и дать свои комментарии 39 | 40 | Кросскомандное ревью может помогать перенимать хорошие практики между командами. Бизнес ревью поможет ответить на вопрос: " отвечает ли API потребностям бизнеса?" 41 | 42 | # Апи опубликовано в общебанковском месте 43 | > Апи опубликовано в backstage 44 | 45 | Единое хранилище необходимо для организации поиска и структурированного, связанного хранения информации 46 | 47 | # Апи опубликовано в человекочитаемом для клиентов (внешних по отношению к банку клиентов) виде 48 | > Есть wiki которая размещена в публичном(вопрос) доступе для партнера 49 | 50 | Не все клиенты имеют развитые ИТ службы, поэтому АПИ надо сопровождать развернутой информацией и представлять в удобном читаемом виде 51 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Реальные кейсы команд банка 2 | 3 | ### Практика API First | Демонстрация от команды CDC Integrations - 22.05.2025 4 | https://train.raiffeisen.ru/node/30305 -------------------------------------------------------------------------------- /getting-started/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started с API First 2 | 3 | > 🎯 Это пошаговое руководство поможет вашей команде начать работать по API First 4 | 5 | - [Getting Started с API First](#getting-started-с-api-first) 6 | - [🤔 Зачем нам API First?](#-зачем-нам-api-first) 7 | - [Проблемы, которые решает API First:](#проблемы-которые-решает-api-first) 8 | - [✅ Чеклист готовности команды](#-чеклист-готовности-команды) 9 | - [Технические требования](#технические-требования) 10 | - [Организационные требования](#организационные-требования) 11 | - [Знания и навыки](#знания-и-навыки) 12 | - [📋 Roadmap внедрения](#-roadmap-внедрения) 13 | - [Итерация 1: Подготовка](#итерация-1-подготовка) 14 | - [Итерация 2: Внедрение](#итерация-2-внедрение) 15 | - [Итерация 3: Первый API](#итерация-3-первый-api) 16 | - [Итерация 4: Интеграция в процессы](#итерация-4-интеграция-в-процессы) 17 | - [❓ Частые вопросы](#-частые-вопросы) 18 | - [Q: Сколько времени займет переход на API First?](#q-сколько-времени-займет-переход-на-api-first) 19 | - [Q: Нужно ли переписывать существующие API?](#q-нужно-ли-переписывать-существующие-api) 20 | - [Q: Что если Backend не успевает за Frontend?](#q-что-если-backend-не-успевает-за-frontend) 21 | - [Q: Как убедить команду в необходимости API First?](#q-как-убедить-команду-в-необходимости-api-first) 22 | - [Q: Что делать, если API часто меняется?](#q-что-делать-если-api-часто-меняется) 23 | - [📚 Что изучить дальше](#-что-изучить-дальше) 24 | - [💬 Нужна помощь?](#-нужна-помощь) 25 | 26 | 27 | ## 🤔 Зачем нам API First? 28 | 29 | ### Проблемы, которые решает API First: 30 | 31 | **Без API First:** 32 | - Frontend и QA ждет, пока Backend допишет endpoints 33 | - Документация не соответствует реальному API 34 | - Интеграция между командами занимает месяцы 35 | - Каждое изменение требует переговоров 36 | 37 | **С API First:** 38 | - Frontend, Backend, QA работают параллельно 39 | - Документация всегда актуальна 40 | - Интеграция начинается с первого дня 41 | - Изменения видны всем сразу 42 | 43 | ## ✅ Чеклист готовности команды 44 | 45 | ### Технические требования 46 | - [ ] Git репозиторий для хранения спецификаций 47 | - [ ] Редактор с поддержкой YAML и OpenAPI (VS Code, IntelliJ IDEA) 48 | 49 | ### Организационные требования 50 | - [ ] Выделенное время на API дизайн (2-4 часа в неделю, слот совместной работы, PBR) 51 | - [ ] Ответственный за API дизайн в команде 52 | - [ ] Поддержка от техлида/продакта 53 | - [ ] Готовность изменить процессы разработки 54 | 55 | ### Знания и навыки 56 | - [ ] Базовое понимание REST API 57 | - [ ] Понимание HTTP методов и статус кодов 58 | - [ ] Умение читать/писать YAML/JSON 59 | - [ ] Понимание формата OpenAPI 60 | - [ ] Готовность учиться новому 61 | 62 | ## 📋 Roadmap внедрения 63 | 64 | ### Итерация 1: Подготовка 65 | - [ ] Провести встречу команды и обсудить API First 66 | - [ ] Выбрать пилотный проект для внедрения 67 | - [ ] Назначить ответственного за API дизайн 68 | - [ ] Изучить [концепции и определения](../concepts/definitions.md) 69 | 70 | ### Итерация 2: Внедрение 71 | - [ ] Определить репозиторий в Gitlab для хранения спецификации ([см. раздел хранение спецификации](../practices/README.md)) 72 | - [ ] Выбрать формат спецификации (OpenAPI 3.0.* рекомендуется) 73 | - [ ] Изучить [правила проектирования API](../rules/rules.md) 74 | 75 | ### Итерация 3: Первый API 76 | - [ ] Настроить редактор спецификаций (VS Code + расширения) ([см. Редакторы спецификациий](../tools/README.md)) 77 | - [ ] Создать первую спецификацию API в формате OpenAPI 78 | - [ ] Опубликовать спецификацию в репозиторий команды 79 | - [ ] Провести API Review внутри команды 80 | - [ ] Начать параллельную разработку Backend/Frontend/QA 81 | 82 | ### Итерация 4: Интеграция в процессы 83 | - [ ] Опубликовать API на внутреннем портале [см. Публикация API](../publishing/README.md) 84 | - [ ] Интегрировать валидацию в CI/CD [см. Валидация](../tools/README.md) 85 | - [ ] Настроить кодогенерацию(backend, frontend, qa) [см. Кодогенерация](../tools/README.md) 86 | - [ ] Настроить mock-сервис [см. Mock-сервисы](../tools/README.md) 87 | - [ ] Оцените готовность команды [см. Оценка зрелости команды](../concepts/team-maturity.md) 88 | - [ ] Провести ретроспективу и зафиксировать результаты 89 | 90 | ## ❓ Частые вопросы 91 | 92 | ### Q: Сколько времени займет переход на API First? 93 | **A:** Первые результаты вы увидите через 2-4 недели. Полный переход команды обычно занимает 2-3 месяца. 94 | 95 | ### Q: Нужно ли переписывать существующие API? 96 | **A:** Нет, начните с новых API. Существующие можно документировать постепенно. 97 | 98 | ### Q: Что если Backend не успевает за Frontend? 99 | **A:** Это нормально! Frontend продолжает работать с mock-сервером, а Backend подключается, когда готов. 100 | 101 | ### Q: Как убедить команду в необходимости API First? 102 | **A:** Покажите результаты на пилотном проекте. Цифры убеждают лучше слов. 103 | 104 | ### Q: Что делать, если API часто меняется? 105 | **A:** Это признак недостаточной проработки на этапе дизайна. Уделите больше времени API Review. 106 | 107 | ## 📚 Что изучить дальше 108 | 109 | - [Инструменты для API First](../tools/README.md) 110 | - [Лучшие практики API First](../practices/README.md) 111 | - [Примеры реальных команд](../examples/README.md) 112 | - [API Review процесс](../practices/README.md) 113 | 114 | ## 💬 Нужна помощь? 115 | 116 | - Присоединяйтесь к чату **[raif-api](https://mattermost.raiffeisen.ru/raiffeisenbank/channels/raif-api)** 117 | - Пригласите API эксперта на встречу вашей команды 118 | 119 | --- 120 | 121 | > 🚀 **Помните**: API First - это не про технологии, а про изменение подхода к разработке. Начните с малого и двигайтесь постепенно! -------------------------------------------------------------------------------- /img/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /img/api-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raiffeisen-DGTL/rest-api-guide/15ad3bd7cae95e1c29f093f8e7e916fba29bad90/img/api-process.png -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Raiffeisen-DGTL/rest-api-guide/15ad3bd7cae95e1c29f093f8e7e916fba29bad90/img/logo.png -------------------------------------------------------------------------------- /img/src/api-first-process.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /img/src/api-process.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /practices/README.md: -------------------------------------------------------------------------------- 1 | # Практики API First 2 | 3 | > 🎯 Проверенные подходы к организации процессов разработки по API First 4 | 5 | 6 | - [Практики API First](#практики-api-first) 7 | - [Contract First Design](#contract-first-design) 8 | - [Что это?](#что-это) 9 | - [Как организовать процесс](#как-организовать-процесс) 10 | - [1. Kick-off встреча](#1-kick-off-встреча) 11 | - [2. Итеративная доработка](#2-итеративная-доработка) 12 | - [3. Финализация контракта](#3-финализация-контракта) 13 | - [Лучшие практики](#лучшие-практики) 14 | - [Антипаттерны](#антипаттерны) 15 | - [API Review процесс](#api-review-процесс) 16 | - [Уровни Review](#уровни-review) 17 | - [1. Внутрикомандное Review](#1-внутрикомандное-review) 18 | - [2. Кросскомандное Review](#2-кросскомандное-review) 19 | - [3. Бизнес Review](#3-бизнес-review) 20 | - [4. Клиентское Review](#4-клиентское-review) 21 | - [Общий процесс проведения ревью](#общий-процесс-проведения-ревью) 22 | - [Инструменты для Review](#инструменты-для-review) 23 | - [Хранение спецификаций](#хранение-спецификаций) 24 | - [Подходы к организации](#подходы-к-организации) 25 | - [1. Монорепозиторий API](#1-монорепозиторий-api) 26 | - [2. API в репозитории сервиса](#2-api-в-репозитории-сервиса) 27 | 28 | 29 | 30 | ## Contract First Design 31 | 32 | ### Что это? 33 | Подход, при котором контракт (спецификация API) создается до написания кода и является договоренностью между всеми участниками разработки. 34 | 35 | ### Как организовать процесс 36 | 37 | #### 1. Kick-off встреча 38 | - **Участники**: Product Owner, Tech Lead, Backend, Frontend, Mobile, QA 39 | - **Результат**: Черновик API спецификации 40 | 41 | **Agenda:** 42 | - Обзор бизнес-требований 43 | - Определение ресурсов и endpoints 44 | - Проектирование моделей данных 45 | - Обсуждение edge cases 46 | 47 | #### 2. Итеративная доработка 48 | - Создание MR с черновиком спецификации 49 | - Комментарии и предложения от всех участников 50 | - Ежедневные 15-минутные синки при необходимости 51 | 52 | #### 3. Финализация контракта 53 | - API Review (см. ниже) 54 | - Фиксация версии 55 | - Запуск разработки 56 | 57 | ### Лучшие практики 58 | - ✅ **Вовлекайте всех с самого начала** - Frontend знает, какие данные нужны для UI. QA знает какие кейсы нужно покрыть. 59 | - ✅ **Думайте о будущем** - Закладывайте расширяемость, но не over-engineering 60 | - ✅ **Документируйте API** - Реальные примеры запросов/ответов и описание модели данных помогает понять API 61 | 62 | ### Антипаттерны 63 | - ❌ Backend создает API в изоляции 64 | - ❌ Frontend "подстраивается" под готовое API 65 | - ❌ Изменения вносятся без обсуждения 66 | 67 | ## API Review процесс 68 | 69 | ### Уровни Review 70 | 71 | ```mermaid 72 | graph LR 73 | A[Внутрикомандное Review] --> C[Кросскомандное Review] 74 | C --> D[Бизнес Review] 75 | D --> E[Публикация API] 76 | ``` 77 | 78 | ### 1. Внутрикомандное Review 79 | - **Кто участвует**: Вся команда разработки 80 | - **Фокус**: Соответствие требованиям, полнота, удобство использования 81 | 82 | ### 2. Кросскомандное Review 83 | - **Кто участвует**: API Community, представители смежных команд 84 | - **Фокус**: Соответствие стандартам банка, переиспользование 85 | 86 | ### 3. Бизнес Review 87 | - **Кто участвует**: Product Owners, Бизнес-эксперты 88 | - **Фокус**: Бизнес-ценность, применимость для клиентов 89 | 90 | ### 4. Клиентское Review 91 | - **Кто участвует**: Клиенты банка, партнеры, Product Owners, Бизнес-эксперты 92 | - **Фокус**: Соответствие потребностям клиента, применимость для клиентов 93 | 94 | ### Общий процесс проведения ревью 95 | ```mermaid 96 | graph LR 97 | subgraph s1["Команда"] 98 | n2["Аналитика и декомпозиция"] 99 | n3["Создание MR в GitLab"] 100 | end 101 | subgraph s2["API Community"] 102 | n4["Review"] 103 | end 104 | subgraph s3["PO и Бизнес-эксперты"] 105 | n5["Business Review"] 106 | end 107 | subgraph s4["Разработчики"] 108 | n7["Реализация API"] 109 | end 110 | subgraph s5["Клиенты"] 111 | n8["Review"] 112 | end 113 | n1["User Story"] --> n2 114 | n2 --> n3 115 | n3 --> n4 & n5 & n8 116 | n5 --> n6{"Ревью пройдено?"} 117 | n4 --> n6 118 | n6 -- нет --> n2 119 | n6 --> n7 120 | n8 --> n6 121 | ``` 122 | 123 | ### Инструменты для Review 124 | - **GitLab MR** - основной инструмент для review 125 | - **FigJam** - для визуализации архитектуры 126 | 127 | ## Хранение спецификаций 128 | 129 | ### Подходы к организации 130 | 131 | #### 1. Монорепозиторий API 132 | ``` 133 | api/ 134 | ├── payments/ 135 | │ ├── payment-service/ 136 | │ │ └── openapi.yaml 137 | │ ├── payment-resolver-service/ 138 | │ │ └── openapi.yaml 139 | ├── accounts/ 140 | │ └── accounts-service/ 141 | │ └── openapi.yaml 142 | └── public/ 143 | └── payment-gateway/ 144 | ├── openapi.yaml 145 | ``` 146 | 147 | **Плюсы:** 148 | - ✅ Единое место для всех API 149 | - ✅ Легко переиспользовать API 150 | - ✅ Можно настроить автоматизацию в одном месте 151 | - ✅ Простой поиск 152 | 153 | **Минусы:** 154 | - ❌ Права доступа для всех 155 | - ❌ Еще один репозиторий 156 | - ❌ Нужно придумать удобную структуру для команды 157 | 158 | #### 2. API в репозитории сервиса 159 | ``` 160 | payment-service/ 161 | ├── src/ 162 | │ ├── main/ 163 | │ │ ├── java/ 164 | │ │ └── resources/ 165 | │ │ └── openapi.yaml 166 | │ └── test/ 167 | ├── docs/ 168 | └── tests/ 169 | ``` 170 | или 171 | ``` 172 | payment-service/ 173 | ├── openapi.yaml 174 | ├── src/ 175 | │ ├── main/ 176 | │ │ ├── java/ 177 | │ │ └── resources/ 178 | │ └── test/ 179 | ├── docs/ 180 | └── tests/ 181 | ``` 182 | 183 | **Плюсы:** 184 | - ✅ API рядом с кодом 185 | - ✅ Версионирование вместе с сервисом 186 | - ✅ Права доступа совпадают 187 | 188 | **Минусы:** 189 | - ❌ Сложнее найти все API 190 | - ❌ Автоматизацию нужно настраивать в каждом репозитории 191 | 192 | --- 193 | 194 | > 💡 **Помните**: Практики - это не догма. Адаптируйте их под нужды вашей команды и проекта. -------------------------------------------------------------------------------- /publishing/README.md: -------------------------------------------------------------------------------- 1 | # Публикация API 2 | 3 | > 🚀 Как опубликовать ваше API на внутреннем или внешнем портале банка 4 | 5 | ## 📑 Содержание 6 | 7 | - [Публикация API](#публикация-api) 8 | - [📑 Содержание](#-содержание) 9 | - [Типы порталов](#типы-порталов) 10 | - [Внешний API Portal](#внешний-api-portal) 11 | - [Внутренний API Portal](#внутренний-api-portal) 12 | - [Процесс публикации](#процесс-публикации) 13 | - [Внутренний портал](#внутренний-портал) 14 | - [Внешний портал](#внешний-портал) 15 | - [FAQ](#faq) 16 | - [Q: Где я могу уточнить вопросы по публикации API](#q-где-я-могу-уточнить-вопросы-по-публикации-api) 17 | - [Q: Когда будет готов автоматический процесс публикации?](#q-когда-будет-готов-автоматический-процесс-публикации) 18 | - [Q: Нужно ли мне переписывать API чтобы он соответствовал API Guide для публикации на порталы?](#q-нужно-ли-мне-переписывать-api-чтобы-он-соответствовал-api-guide-для-публикации-на-порталы) 19 | - [Q: Кто может публиковать API?](#q-кто-может-публиковать-api) 20 | - [Q: Сколько времени занимает публикация?](#q-сколько-времени-занимает-публикация) 21 | 22 | 23 | ## Типы порталов 24 | 25 | ### Внешний API Portal 26 | - **URL**: https://developer.raiffeisen.ru 27 | - **Аудитория**: Клиенты и партнеры банка 28 | - **Цель**: Интеграция с продуктами банка 29 | - **Уровень API**: Внешнее API (Public API) 30 | 31 | ### Внутренний API Portal 32 | - **URL**: В работе - 30 июня 2025 33 | - **Аудитория**: Команды внутри банка 34 | - **Цель**: Переиспользование API между командами 35 | - **Уровень API**: Внутреннее API (Private API) 36 | 37 | 38 | ## Процесс публикации 39 | 40 | ### Внутренний портал 41 | 42 | - [Публикация внутреннего API](https://docs.cdci.raiffeisen.ru/raif-api-public-doc/raif-api-private/publikaciya-api) 43 | 44 | ### Внешний портал 45 | 46 | - [Публикация Public API (Ручной процесс)](https://docs.cdci.raiffeisen.ru/raif-api-public-doc/raif-api/publikaciya-api/publikaciya-vneshnikh-api) 47 | - Work in Progress - [Публикация Public API](https://docs.cdci.raiffeisen.ru/raif-api-public-doc/raif-api/publikaciya-api/process-publikacii-api) 48 | 49 | 50 | ## FAQ 51 | 52 | ### Q: Где я могу уточнить вопросы по публикации API 53 | **A:** В чате **[raif-api](https://mattermost.raiffeisen.ru/raiffeisenbank/channels/raif-api)** можно задать любые вопросы по публикации внешних/внутренних API 54 | 55 | ### Q: Когда будет готов автоматический процесс публикации? 56 | **A:** В начале Q3(конце июня/начало июля 2025) 57 | 58 | ### Q: Нужно ли мне переписывать API чтобы он соответствовал API Guide для публикации на порталы? 59 | **A:** Для внешних API и публикации на внешний портал требуется соответствие API Guide. Для внутренних API в 2025 году соответствие API Guide не требуется, публиковать можно любые имеющиеся APIю 60 | 61 | ### Q: Кто может публиковать API? 62 | **A:** Любая команда для внутреннего портала. Для внешнего нужно одобрение бизнеса. 63 | 64 | ### Q: Сколько времени занимает публикация? 65 | **A:** Публикация на портал полностью автоматическая через Gitlab CI. Время публикации зависит от размера API. Обычно не дольше 10-15 минут. 66 | 67 | --- 68 | 69 | > 💡 **Важно**: Публикация API - это не конец, а начало. Готовьтесь к поддержке, развитию и работе с вашим потребителем API. -------------------------------------------------------------------------------- /rules/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Как внести вклад в API Best Practices 2 | Мы рады любым предложениям по улучшению стандартов API нашего банка. Этот документ описывает процесс внесения изменений в API Guide. 3 | 4 | - [Как внести вклад в API Best Practices](#как-внести-вклад-в-api-best-practices) 5 | - [Общий процесс внесения изменений](#общий-процесс-внесения-изменений) 6 | - [Детальный процесс](#детальный-процесс) 7 | - [1. Ознакомление с текущим гайдом](#1-ознакомление-с-текущим-гайдом) 8 | - [2. Создание Issue (рекомендуется)](#2-создание-issue-рекомендуется) 9 | - [3. Подготовка Merge Request](#3-подготовка-merge-request) 10 | - [4. Процесс рассмотрения](#4-процесс-рассмотрения) 11 | - [5. Критерии принятия изменений](#5-критерии-принятия-изменений) 12 | - [Команды Maintainers](#команды-maintainers) 13 | - [Жизненный цикл правил](#жизненный-цикл-правил) 14 | - [Контакты](#контакты) 15 | - [Лицензия](#лицензия) 16 | 17 | ### Общий процесс внесения изменений 18 | 1. Ознакомьтесь с текущей версией стандартов API в [rules.md](rules.md) 19 | 2. [Создайте Issue](https://gitlabci.raiffeisen.ru/cib/api-guide/-/issues) для обсуждения предлагаемых изменений (опционально, но рекомендуется) 20 | 3. Подготовьте Merge Request с предлагаемыми изменениями 21 | 4. Дождитесь рассмотрения от [команды maintainers](#команды-maintainers) 22 | 5. Внесите правки (если потребуется) по результатам обсуждения 23 | 6. После одобрения ваши изменения будут включены в основную ветку 24 | 25 | ### Детальный процесс 26 | 27 | #### 1. Ознакомление с текущим гайдом 28 | Перед предложением изменений, пожалуйста, внимательно ознакомьтесь с: 29 | - Текущей версией [API Guide](rules.md) 30 | - [Открытыми и закрытыми Issue](https://gitlabci.raiffeisen.ru/cib/api-guide/-/issues), чтобы убедиться, что ваше предложение не дублирует существующие 31 | - Историей изменений гайда за последнее время 32 | 33 | #### 2. Создание Issue (рекомендуется) 34 | Перед созданием Merge Request рекомендуется сначала [создать issue](https://gitlabci.raiffeisen.ru/cib/api-guide/-/issues) для обсуждения предлагаемых изменений: 35 | - Используйте шаблон "API Guide Change Proposal" 36 | - Четко опишите проблему или улучшение, которое вы предлагаете 37 | - Укажите обоснование для предлагаемых изменений 38 | - По возможности, приведите примеры использования 39 | 40 | #### 3. Подготовка Merge Request 41 | Когда вы готовы предложить изменения: 42 | 1. Создайте новую ветку из main с названием, отражающим суть изменений 43 | ``` 44 | git checkout -b add-new-rule-for-authentication 45 | ``` 46 | 2. Внесите изменения в соответствующие файлы гайда 47 | 3. Если вы добавляете новое правило, следуйте [установленному формату](rule-format.md): 48 | 4. Создайте Merge Request 49 | 5. В описании MR укажите: 50 | - Ссылку на Issue (если он был создан) 51 | - Краткое описание изменений 52 | - Обоснование изменений 53 | - Связанную документацию или ресурсы 54 | 6. Отправьте ссылку на Merge Request в чат [~cib_api_first](https://mattermost.raiffeisen.ru/raiffeisenbank/channels/cib_api_first) 55 | 56 | #### 4. Процесс рассмотрения 57 | После создания Merge Request: 58 | 1. Maintainers от двух команд рассмотрят ваши изменения 59 | 2. В процессе обсуждения могут быть запрошены дополнительные комментарии или изменения 60 | 3. Для принятия изменений требуется положительное решение от всех [команд maintainers](#команды-maintainers) 61 | 62 | #### 5. Критерии принятия изменений 63 | Предложенные изменения должны соответствовать следующим критериям: 64 | - Не противоречить общей концепции API Guide 65 | - Быть достаточно обоснованными и актуальными 66 | - Быть практически применимыми 67 | - Иметь четкое и понятное описание 68 | - По возможности, включать примеры автоматизации проверки 69 | 70 | ### Команды Maintainers 71 | Решения о принятии изменений принимаются двумя командами maintainers: 72 | - [Команда Raif API](https://insider.raiffeisen.ru/agile-team/180) 73 | - [Команда Raif Pay](https://insider.raiffeisen.ru/employees/dashboard/functional-team/923) 74 | 75 | ### Жизненный цикл правил 76 | Каждое правило в гайде имеет свой жизненный цикл: 77 | 1. Предложено - правило предложено, но еще не принято 78 | 2. Принято - правило утверждено и включено в гайд 79 | 3. Устарело - правило помечено как устаревшее, но еще действует 80 | 4. Удалено - правило больше не действует 81 | ### Контакты 82 | Если у вас возникли вопросы, вы можете связаться с командами maintainers: 83 | - Команда API Standards: #api-standards в корпоративном Slack 84 | - Команда Bank API: #bank-api в корпоративном Slack 85 | ### Лицензия 86 | Внося изменения в API-гайд, вы соглашаетесь с тем, что ваш вклад будет доступен под той же внутренней лицензией, что и сам гайд. -------------------------------------------------------------------------------- /rules/rule-format.md: -------------------------------------------------------------------------------- 1 | # Формат правил в API Best Practices 2 | 3 | - [Формат правил в API Best Practices](#формат-правил-в-api-best-practices) 4 | - [Обязательность](#обязательность) 5 | - [Содержимое правила](#содержимое-правила) 6 | - [Пример правила](#пример-правила) 7 | - [Использование kebab-case для пути](#использование-kebab-case-для-пути) 8 | - [Описание правила](#описание-правила) 9 | - [Обоснование](#обоснование) 10 | 11 | 12 | ### Обязательность 13 | Индикатор обязательности правил(Severity) имеет 2 значения 14 | - MUST - соблюдаем обязательно 15 | - RECOMMENDATION - рекомендуется для соблюдения 16 | 17 | 18 | ### Содержимое правила 19 | - Название, ID, Severity(MUST, RECOMMENDATION) 20 | - Описание с примерами(правильно, неправильно) 21 | - Обоснование(почему именно это решение принято, какие были альтернативы) 22 | 23 | ### Пример правила 24 | 25 | #### Использование kebab-case для пути 26 | 27 | | ID | Severity | Дата принятия | 28 | |-----------------|----------|---------------| 29 | | path-kebab-case | Must | 27.02.2025 | 30 | 31 | ##### Описание правила 32 | 33 | Пути API должны использовать kebab-case (строчные буквы с разделением дефисами) для наименования. 34 | 35 | Правильно: 36 | ``` 37 | /v1/statements 38 | /v1/payment-orders/ 39 | ``` 40 | Неправильно: 41 | ``` 42 | /v1/paymentOrders // camelCase 43 | /v1/PaymentOrders // PascalCase 44 | /v1/payment_orders // snake_case 45 | 46 | ``` 47 | ##### Обоснование 48 | 49 | Использование kebab-case обеспечивает единообразие API и соответствует лучшим практикам именования ресурсов в REST API. 50 | Чтобы ваши URI было легче сканировать и интерпретировать, используйте символ дефиса (-), чтобы улучшить читаемость имен в сегментах длинных путей. 51 | 52 | Были рассмотрены альтернативные стили именования: 53 | - camelCase - отклонён из-за проблем с регистро-зависимостью в некоторых системах 54 | - snake_case - отклонён для сохранения единообразия 55 | - PascalCase - отклонён из-за проблем с читаемостью URL 56 | 57 | --- -------------------------------------------------------------------------------- /rules/rules-process.md: -------------------------------------------------------------------------------- 1 | 2 | # Процесс изменения правил 3 | 4 | - [Процесс изменения правил](#процесс-изменения-правил) 5 | - [Глоссарий](#глоссарий) 6 | - [Общее и частное](#общее-и-частное) 7 | - [Процесс изменения правил](#процесс-изменения-правил-1) 8 | - [Описание процесса изменения правил](#описание-процесса-изменения-правил) 9 | - [Обратная совместимость правил](#обратная-совместимость-правил) 10 | - [Как мы будем взаимодействовать с API](#как-мы-будем-взаимодействовать-с-api) 11 | - [Централизованный гейтвей(Integrations, RBO, Mobile)](#централизованный-гейтвейintegrations-rbo-mobile) 12 | - [Разные гейтвеи для продуктов](#разные-гейтвеи-для-продуктов) 13 | - [Где мы храним и публикуем правила?](#где-мы-храним-и-публикуем-правила) 14 | - [Обязательность правил](#обязательность-правил) 15 | 16 | 17 | ### Глоссарий 18 | 19 | - **Принцип** - общее положение или утверждение, на основе которого формируются правила. 20 | - **Правило** - требование на соблюдение каких-либо условий, имеющее определенную обязательность(Severity). 21 | - **Severity** - Индикатор обязательности правила. Имеет 2 значения(MUST, RECOMMENDATION). MUST - соблюдаем обязательно. RECOMMENDATION - рекомендуется для соблюдения. 22 | - **Гайд** - документ, который содержит принципы и правила. 23 | - **Maintainer** - человек или команда отвечающие за процесс изменения гайда. 24 | - **Contributor** - инициатор изменений в гайд. 25 | 26 | 27 | ### Общее и частное 28 | - Есть общая часть и мы стараемся все правила закладывать в общий гайд. 29 | - Правила накладываются на все уровни API(внешние, внутренние, продуктовые) 30 | - Специфика продукта не должна конфликтовать с общими правилами 31 | 32 | ### Процесс изменения правил 33 | - Команды Raif Pay и Raif API являются одними из команд-мейнтейнеров процесса изменения правил 34 | - Решения об изменении правил принимаются с апрувом каждого мейнтейнера процесса 35 | - Финальное решение по принятию изменений в гайд согласуется между мейнтенарами 36 | 37 | #### Описание процесса изменения правил 38 | 39 | В процессе разработки или ревью API может возникнуть ситуация когда мы понимаем что гайд либо устарел, либо противоречит здравому смыслу, либо мы хотим что-то добавить в гайд. 40 | 41 | - Описываем предлагаемые изменения, согласно формату правил приведенному в отдельном документе, с обоснованием предлагаемого изменения. Создаем MR и скидываем в чат сообщества [~cib_api_first](https://mattermost.raiffeisen.ru/raiffeisenbank/channels/cib_api_first)? 42 | - Новости, дайджесты и use-cases в канал [~raif-api](https://mattermost.raiffeisen.ru/raiffeisenbank/channels/raif-api) 43 | - Обязанность сообщества проводить review предлагаемых MR. 44 | - Для решения некоторых вопросов могут быть организованы встречи. Решение по встрече формируется в процессе обсуждения MR. Мейнтейнеры сообщества приоритизируют и создают встречу по предлагаемому изменению. 45 | 46 | #### Обратная совместимость правил 47 | - Если вышла новая версия гайда с ломающими изменениями, то API разработанные ранее самостоятельно решают о необходимости доработок 48 | - TBD - версионирование гайда 49 | 50 | #### Как мы будем взаимодействовать с API 51 | 52 | - TBD - хотим ли мы добавить в обсуждения гайда API First другие темы из релизного цикла API(публикация в каналы, инструменты, внедрение подходов) 53 | 54 | ##### Централизованный гейтвей(Integrations, RBO, Mobile) 55 | - `api.raiffeisen.ru` - гейтвей для доступа к API продуктов 56 | 57 | Пример API на гейтвее: 58 | - `api.raiffeisen.ru/fx/v1/trades/1` 59 | 60 | Если мы будем публиковать внутренние API в канале Raif API, они будут доступны каким-то способом(ниже примеры) 61 | - `api.raiffeisen.ru/internal/fx/v1/trades/1` 62 | - `internal.api.raiffeisen.ru/fx/v1/trades/1` 63 | - `api.raiffeisen.ru/fx/beta/trades/1` 64 | 65 | ##### Разные гейтвеи для продуктов 66 | - Обсуждаем конкретные кейсы с командами 67 | 68 | --- 69 | 70 | #### Где мы храним и публикуем правила? 71 | - Gitlab - храним правила в репозитории https://gitlabci.raiffeisen.ru/cib/api-guide 72 | - Формируем артефакты(принципы, правила) заново 73 | - Raif API ссылается(визуализирует) правила в Gramax(портал документации) 74 | 75 | #### Обязательность правил 76 | Обязательность(Severity) для правил пока выделяем 2-ух типов: 77 | - MUST - соблюдаем обязательно 78 | - RECOMMENDATION - рекомендуется для соблюдения 79 | -------------------------------------------------------------------------------- /rules/rules-structure.md: -------------------------------------------------------------------------------- 1 | На основе вашего существующего документа, я предлагаю следующие логические категории для группировки правил API: 2 | 1. Архитектура API 3 | - Принципы REST 4 | - Модель зрелости Richardson 5 | - Общая структура API 6 | 2. Именование и структура ресурсов 7 | - Форматы путей и эндпоинтов 8 | - Стили именования (kebab-case, camelCase) 9 | - Структура URL (версионирование, шаблоны) 10 | - Антипаттерны в именовании 11 | 3. Методы HTTP и их использование 12 | - Правила использования GET, POST, PUT, PATCH, DELETE 13 | - Идемпотентность операций 14 | - Безопасные и небезопасные методы 15 | 4. Аутентификация и авторизация 16 | - Способы аутентификации 17 | - Обработка токенов 18 | - Уровни доступа 19 | - Безопасные практики 20 | 5. Управление версиями API 21 | - Обратно-совместимые изменения 22 | - Ломающие изменения 23 | - Стратегии версионирования 24 | 6. Форматы данных и сериализация 25 | - Форматы дат и времени 26 | - Представление валют и денежных сумм 27 | - Коды стран и языков 28 | - Стандартные форматы для специальных типов данных 29 | 7. Обработка параметров и запросов 30 | - Передача массивов в параметрах 31 | - Фильтрация 32 | - Пагинация (курсорная, offset) 33 | - Сортировка 34 | 8. Обработка ошибок и исключений 35 | - HTTP коды состояния 36 | - Структура ответов с ошибками 37 | - Детализация ошибок 38 | - Обработка валидационных ошибок 39 | 9. Документация API 40 | - Требования к описанию методов 41 | - Примеры значений 42 | - Спецификация OpenAPI/Swagger 43 | 10. Производительность и оптимизация 44 | - Размеры ответов 45 | - Ограничения на пагинацию 46 | - Кэширование 47 | - Оптимизация запросов 48 | 11. Идентификаторы и управление данными 49 | - Уникальные идентификаторы 50 | - Сквозные идентификаторы 51 | - Связи между объектами 52 | 12. Тестирование и валидация API 53 | - Требования к тестированию 54 | - Автоматическая валидация 55 | - Инструменты для тестирования 56 | Эти категории достаточно универсальны и охватывают большинство аспектов API, описанных в вашем документе. При необходимости вы можете добавить дополнительные категории или объединить некоторые из предложенных, в зависимости от специфики вашего API и потребностей команды. 57 | Для каждой категории можно присвоить короткий префикс ID, например: 58 | - ARCH- для правил из категории "Архитектура API" 59 | - NAME- для "Именование и структура ресурсов" 60 | - HTTP- для "Методы HTTP и их использование" 61 | - AUTH- для "Аутентификация и авторизация" 62 | - и так далее. 63 | Это поможет быстро идентифицировать, к какой категории относится правило, просто взглянув на его ID. -------------------------------------------------------------------------------- /rules/rules.md: -------------------------------------------------------------------------------- 1 | # API Guide 2 | 3 | - [API Guide](#api-guide) 4 | - [Введение](#введение) 5 | - [Общие рекомендации](#общие-рекомендации) 6 | - [Правила](#правила) 7 | - [Использование kebab-case для пути](#использование-kebab-case-для-пути) 8 | - [Описание правила](#описание-правила) 9 | - [Обоснование](#обоснование) 10 | - [Избегать избыточных префиксов в пути](#избегать-избыточных-префиксов-в-пути) 11 | - [Описание правила](#описание-правила-1) 12 | - [Обоснование](#обоснование-1) 13 | - [Используем для именования параметров запроса camelCase](#используем-для-именования-параметров-запроса-camelcase) 14 | - [Описание правила](#описание-правила-2) 15 | - [Обоснование](#обоснование-2) 16 | - [Используем для именования полей тела запроса camelCase](#используем-для-именования-полей-тела-запроса-camelcase) 17 | - [Описание правила](#описание-правила-3) 18 | - [Обоснование](#обоснование-3) 19 | - [Используем camelCase для operationId метода](#используем-camelcase-для-operationid-метода) 20 | - [Описание правила](#описание-правила-4) 21 | - [Обоснование](#обоснование-4) 22 | - [Выносим тело запроса и ответа методов в отдельный блок](#выносим-тело-запроса-и-ответа-методов-в-отдельный-блок) 23 | - [Описание правила](#описание-правила-5) 24 | - [Обоснование](#обоснование-5) 25 | - [Объекты запросов и ответов именуются стилем PascalCase с постфиксами `Request/Response`](#объекты-запросов-и-ответов-именуются-стилем-pascalcase-с-постфиксами-requestresponse) 26 | - [Описание правила](#описание-правила-6) 27 | - [Обоснование](#обоснование-6) 28 | - [Выделяем части запросов/ответов в отдельные объекты](#выделяем-части-запросовответов-в-отдельные-объекты) 29 | - [Описание правила](#описание-правила-7) 30 | - [Обоснование](#обоснование-7) 31 | - [Используем UPPER\_SNAKE\_CASE для Enum и mapping для discriminator](#используем-upper_snake_case-для-enum-и-mapping-для-discriminator) 32 | - [Описание правила](#описание-правила-8) 33 | - [Обоснование](#обоснование-8) 34 | - [Пагинация](#пагинация) 35 | - [offset-пагинация (page,size)](#offset-пагинация-pagesize) 36 | - [Описание правила](#описание-правила-9) 37 | - [cursor-пагинация](#cursor-пагинация) 38 | - [Описание правила](#описание-правила-10) 39 | - [Сортировка](#сортировка) 40 | - [Описание правила](#описание-правила-11) 41 | - [Фильтрация](#фильтрация) 42 | - [Описание правила](#описание-правила-12) 43 | - [Используй формат даты-времени ISO 8601](#используй-формат-даты-времени-iso-8601) 44 | - [Описание правила](#описание-правила-13) 45 | - [Обоснование](#обоснование-9) 46 | - [используй формат стран ISO 3166](#используй-формат-стран-iso-3166) 47 | - [Описание правила](#описание-правила-14) 48 | - [Обоснование](#обоснование-10) 49 | - [используй формат стран ISO 4217](#используй-формат-стран-iso-4217) 50 | - [Описание правила](#описание-правила-15) 51 | - [Обоснование](#обоснование-11) 52 | - [Используй версионирование в URL](#используй-версионирование-в-url) 53 | - [Описание правила](#описание-правила-16) 54 | - [Обоснование](#обоснование-12) 55 | - [Учитывай обратную совместимость API](#учитывай-обратную-совместимость-api) 56 | - [Описание правила](#описание-правила-17) 57 | - [Обоснование](#обоснование-13) 58 | - [Соблюдайте сигнатуру пути API](#соблюдайте-сигнатуру-пути-api) 59 | - [Описание правила](#описание-правила-18) 60 | - [Обоснование](#обоснование-14) 61 | - [Используй HTTP методы правильно](#используй-http-методы-правильно) 62 | - [Описание правила](#описание-правила-19) 63 | - [GET - для получения данных](#get---для-получения-данных) 64 | - [POST - для создания ресурсов](#post---для-создания-ресурсов) 65 | - [PUT - для полного обновления ресурса](#put---для-полного-обновления-ресурса) 66 | - [PATCH - для частичного обновления](#patch---для-частичного-обновления) 67 | - [DELETE - для удаления ресурсов](#delete---для-удаления-ресурсов) 68 | - [Обоснование](#обоснование-15) 69 | - [API для скачивания файлов обязано поддерживать HEAD запрос](#api-для-скачивания-файлов-обязано-поддерживать-head-запрос) 70 | - [Описание правила](#описание-правила-20) 71 | - [Обоснование](#обоснование-16) 72 | - [Заполняй примеры в документации](#заполняй-примеры-в-документации) 73 | - [Описание правила](#описание-правила-21) 74 | - [Обоснование](#обоснование-17) 75 | - [Не используй статусы перенаправления запроса](#не-используй-статусы-перенаправления-запроса) 76 | - [Описание правила](#описание-правила-22) 77 | - [Обоснование](#обоснование-18) 78 | - [Используй только наиболее распространенные коды состояния HTTP](#используй-только-наиболее-распространенные-коды-состояния-http) 79 | - [Описание правила](#описание-правила-23) 80 | - [Легенда](#легенда) 81 | - [Успешные коды](#успешные-коды) 82 | - [200 OK](#200-ok) 83 | - [201 Created](#201-created) 84 | - [202 Accepted](#202-accepted) 85 | - [204 No content](#204-no-content) 86 | - [205 Reset Content](#205-reset-content) 87 | - [206 Partial Content](#206-partial-content) 88 | - [207 Multi-Status](#207-multi-status) 89 | - [Перенаправление(redirect)](#перенаправлениеredirect) 90 | - [301 Moved Permanently](#301-moved-permanently) 91 | - [302 Found](#302-found) 92 | - [303 See Other](#303-see-other) 93 | - [304 Not Modified](#304-not-modified) 94 | - [307 Temporary Redirect](#307-temporary-redirect) 95 | - [308 Permanent Redirect](#308-permanent-redirect) 96 | - [Ошибки клиента](#ошибки-клиента) 97 | - [400 Bad Request](#400-bad-request) 98 | - [401 Unauthorized](#401-unauthorized) 99 | - [403 Forbidden](#403-forbidden) 100 | - [404 Not found](#404-not-found) 101 | - [405 Method Not Allowed](#405-method-not-allowed) 102 | - [406 Not Acceptable](#406-not-acceptable) 103 | - [408 Request timeout](#408-request-timeout) 104 | - [409 Conflict](#409-conflict) 105 | - [410 Gone](#410-gone) 106 | - [411 Length Required](#411-length-required) 107 | - [412 Precondition Failed](#412-precondition-failed) 108 | - [415 Unsupported Media Type](#415-unsupported-media-type) 109 | - [417 Expectation Failed](#417-expectation-failed) 110 | - [418 I’m a teapot 🫖](#418-im-a-teapot-) 111 | - [422 Unprocessable Content](#422-unprocessable-content) 112 | - [423 Locked](#423-locked) 113 | - [424 Failed Dependency](#424-failed-dependency) 114 | - [428 Precondition Required](#428-precondition-required) 115 | - [429 Too many requests](#429-too-many-requests) 116 | - [431 Request Header Fields Too Large](#431-request-header-fields-too-large) 117 | - [Ошибки сервера](#ошибки-сервера) 118 | - [500 Internal Server Error](#500-internal-server-error) 119 | - [501 Not Implemented](#501-not-implemented) 120 | - [502 Bad Gateway](#502-bad-gateway) 121 | - [503 Service Unavailable](#503-service-unavailable) 122 | - [504 Gateway Timeout](#504-gateway-timeout) 123 | - [505 HTTP Version Not Supported](#505-http-version-not-supported) 124 | - [507 Insufficient Storage](#507-insufficient-storage) 125 | - [511 Network Authentication Required](#511-network-authentication-required) 126 | 127 | 128 | # Введение 129 | 130 | Данный гайд содержит основные принципы и правила, которым мы следуем при разработке REST API в Райффайзен Банке. 131 | Правила разделены по тематическим разделам. 132 | У каждого правила есть: 133 | 134 | - *ID* - уникальный идентификатор правила 135 | - *Severity* - индикатор, является ли правило обязательным(MUST) или рекомендацией(RECOMMENDATION) 136 | - *Дата принятия* - когда это правило было добавлено в гайд 137 | 138 | # Общие рекомендации 139 | 140 | REST ([Representational State Transfer](https://en.wikipedia.org/wiki/Representational_state_transfer)) - это архитектурная абстракция, которая описывает взаимодействией компонентов в распределенной системе. REST широко используется для создания web API (*RESTful web API*), которое использует протокол HTTP как транспорт. 141 | 142 | В RESTful web API обращение к ресурсу происходит по уникальному идентификатору (*URL*), с указанием действия над ресурсом (*HTTP method*), в запросе может передаваться тело запроса (*body*) и дополнительные заголовки (*HTTP header fields*). В ответ на запрос, ресурс возвращает код ответа (*HTTP status code*) и **может** возвращаться тело ответа. 143 | 144 | В качество формата тела запроса/ответа рекомендуется использовать только JSON. Использование других форматов (XML/TXT) возможно в исключительных случаях. 145 | 146 | Мы ориентируемся на [Richardson Maturity Model](https://martinfowler.com/articles/richardsonMaturityModel.html), но считаем избыточным Level 3 147 | 148 | # Правила 149 | 150 | ### Использование kebab-case для пути 151 | 152 | | ID | Severity | Дата принятия | 153 | |-----------------|----------|---------------| 154 | | path-kebab-case | MUST | 27.02.2025 | 155 | 156 | #### Описание правила 157 | 158 | Пути API должны использовать kebab-case (строчные буквы с разделением дефисами) для наименования. 159 | 160 | Правильно: 161 | ``` 162 | /v1/statements 163 | /v1/payment-orders/ 164 | ``` 165 | Неправильно: 166 | ``` 167 | /v1/paymentOrders // camelCase 168 | /v1/PaymentOrders // PascalCase 169 | /v1/payment_orders // snake_case 170 | 171 | ``` 172 | #### Обоснование 173 | 174 | Использование kebab-case обеспечивает единообразие API и соответствует лучшим практикам именования ресурсов в REST API. 175 | Чтобы ваши URI было легче сканировать и интерпретировать, используйте символ дефиса (-), чтобы улучшить читаемость имен в сегментах длинных путей. 176 | 177 | Были рассмотрены альтернативные стили именования: 178 | - camelCase - отклонён из-за проблем с регистро-зависимостью в некоторых системах 179 | - snake_case - отклонён для сохранения единообразия 180 | - PascalCase - отклонён из-за проблем с читаемостью URL 181 | 182 | --- 183 | 184 | ### Избегать избыточных префиксов в пути 185 | 186 | | ID | Severity | Дата принятия | 187 | |----------------------------|----------|---------------| 188 | | path-no-redundant-prefixes | MUST | 27.02.2025 | 189 | 190 | 191 | #### Описание правила 192 | 193 | Не следует использовать избыточные термины в методах, не относящиеся к смыслу ресурса/команды, такие как: 194 | - `api` 195 | - `openapi` 196 | - `http` 197 | - `service` 198 | 199 | > Префикс `*.raiffeisen.ru/api` или поддомен `api.raiffeisen.ru/...` допускается на уровне gateway, но не допускается в пути метода API. Подробнее см. [Следуйте структуре пути API](#следуйте-структуре-пути-api) 200 | 201 | Правильно: 202 | ``` 203 | /v1/statements 204 | /v1/statements/export 205 | 206 | ``` 207 | 208 | Неправильно: 209 | ``` 210 | /api/v1/statements 211 | /v1/http/statements 212 | /v1/statement-service/export 213 | ``` 214 | 215 | #### Обоснование 216 | 217 | Избыточные префиксы увеличивают длину URL без добавления смысловой нагрузки, усложняют чтение и понимание API. 218 | 219 | При публикации для внешних клиентов на `api.raiffeisen.ru` дополнительный префикс `api` будет создавать избыточность. 220 | 221 | --- 222 | 223 | ### Используем для именования параметров запроса camelCase 224 | 225 | | ID | Severity | Дата принятия | 226 | |-------------------------|----------|---------------| 227 | | query-params-camel-case | MUST | 27.02.2025 | 228 | 229 | 230 | #### Описание правила 231 | 232 | Используем для именования параметров [camelCase](https://en.wiktionary.org/wiki/CamelCase). 233 | 234 | 235 | Правильно: 236 | ``` 237 | /v1/statements?requestId={requestId} 238 | ``` 239 | 240 | Неправильно: 241 | ``` 242 | /v1/statements?request_id={requestId} 243 | /v1/statements?RequestId={requestId} 244 | ``` 245 | 246 | #### Обоснование 247 | 248 | Самым популярным решением для query params в банке является `camelCase`, именно поэтому выбран стандартным способом именования. 249 | 250 | --- 251 | 252 | ### Используем для именования полей тела запроса camelCase 253 | 254 | | ID | Severity | Дата принятия | 255 | |-------------------------|----------|---------------| 256 | | body-fields-camel-case | MUST | 11.03.2025 | 257 | 258 | 259 | #### Описание правила 260 | 261 | Используем для именования полей тела запроса [camelCase](https://en.wiktionary.org/wiki/CamelCase). 262 | 263 | 264 | Правильно: 265 | ```json 266 | { 267 | "productId": "8AD369C0-68B4-4CD2-B78B-413D53AD1E82", 268 | "price": 50, 269 | "createdAt": "2025-03-11T09:14:38+03:00" 270 | ... 271 | } 272 | ``` 273 | 274 | Неправильно: 275 | ```json 276 | { 277 | "product_id": "8AD369C0-68B4-4CD2-B78B-413D53AD1E82", 278 | "UpdatedAt": "2025-03-11T11:12:38+03:00", 279 | "createdat": "2025-03-11T09:14:38+03:00" 280 | ... 281 | } 282 | ``` 283 | 284 | #### Обоснование 285 | 286 | Самым популярным решением для полей тела запроса в банке является `camelCase`, именно поэтому выбран стандартным способом именования. Такое же способ именования используется в параметрах запроса - [Используем для именования параметров запроса camelCase](#используем-для-именования-параметров-запроса-camelcase) 287 | 288 | --- 289 | 290 | ### Используем camelCase для operationId метода 291 | | ID | Severity | Дата принятия | 292 | |---------------------------------|----------|---------------| 293 | | method-operation-id-camel-case | MUST | 13.03.2025 | 294 | 295 | #### Описание правила 296 | 297 | `operationId` - camelCase, содержит в себе короткое название метода (например, `createOrder` или `getPaymentStatus`). 298 | 299 | Правильно: 300 | ```yaml 301 | paths: 302 | '/sbp/v2/qrs/': 303 | post: 304 | operationId: registerQR 305 | ... 306 | ``` 307 | 308 | Неправильно: 309 | ```yaml 310 | paths: 311 | '/sbp/v2/qrs/': 312 | post: 313 | operationId: post-sbp-v2-qrs 314 | ... 315 | ``` 316 | 317 | #### Обоснование 318 | Согласно назначению в спецификации [openapi](https://swagger.io/specification/) поле может использоваться тулами и библиотеками для уникального обозначения метода в коде. Спецификация рекомендует именовать согласоно соглашения о именовании языка программирования. У нас самый популярный язык - это Java, в ней принято использовать для именования методов camelCase 319 | 320 | --- 321 | 322 | ### Выносим тело запроса и ответа методов в отдельный блок 323 | | ID | Severity | Дата принятия | 324 | |-------------------------------------|----------|---------------| 325 | | method-request-response-components | MUST | 13.03.2025 | 326 | 327 | #### Описание правила 328 | Тело запроса и ответа должны быть вынесены в блок [Components Object](https://spec.openapis.org/oas/v3.1.0#components-object) как [Schema](https://spec.openapis.org/oas/v3.1.0#schema). 329 | 330 | Правильно: 331 | ```yaml 332 | paths: 333 | '/sbp/v2/qrs/': 334 | post: 335 | requestBody: 336 | content: 337 | application/json: 338 | schema: 339 | $ref: '#/components/schemas/reqPayQR' 340 | responses: 341 | '200': 342 | description: OK 343 | content: 344 | application/json: 345 | schema: 346 | $ref: '#/components/schemas/qrResponse' 347 | ``` 348 | 349 | Неправильно: 350 | ```yaml 351 | paths: 352 | '/sbp/v2/qrs/': 353 | post: 354 | requestBody: 355 | content: 356 | application/json: 357 | schema: 358 | type: object 359 | properties: 360 | qrId: 361 | type: string 362 | ... 363 | responses: 364 | '200': 365 | description: OK 366 | content: 367 | application/json: 368 | schema: 369 | type: object 370 | properties: 371 | qrId: 372 | type: string 373 | ... 374 | ``` 375 | #### Обоснование 376 | - Улучшает читаемость спецификации тогда как средства отображения АПИ в любом случае позволяют скрывать и раскрывать содержание запросов и ответов. 377 | - Возможность переиспользования объектов запросов и ответов 378 | 379 | --- 380 | 381 | ### Объекты запросов и ответов именуются стилем PascalCase с постфиксами `Request/Response` 382 | | ID | Severity | Дата принятия | 383 | |----------------------------------|--------------------|---------------| 384 | | object-request-response-postfix | RECOMMENDATION | 13.03.2025 | 385 | 386 | #### Описание правила 387 | Объекты запросов и ответов именуются стилем PascalCase с постфиксами `Request/Response` (например, `CreateOrderRequest`). Исключение составляет случай, когда модель присутствует и в запросе, и в ответе. Тогда постфикс опускается. 388 | 389 | #### Обоснование 390 | Улучшает читаемость и структурированность спецификации 391 | 392 | --- 393 | 394 | ### Выделяем части запросов/ответов в отдельные объекты 395 | | ID | Severity | Дата принятия | 396 | |-------------------------------------|----------|---------------| 397 | | object-request-response-extraction | MUST | 13.03.2025 | 398 | 399 | #### Описание правила 400 | - Все объекты, которые используются больше одного раза, должны быть вынесены как отдельные модели/параметры. Их использование происходит с помощью [ссылок](https://spec.openapis.org/oas/v3.1.0#reference-object) `$ref`. 401 | 402 | Правильно 403 | ```yaml 404 | orderCreationResponse: 405 | properties: 406 | status: 407 | $ref: '#/components/schemas/Status' 408 | orderCreationResponse: 409 | properties: 410 | status: 411 | $ref: '#/components/schemas/Status' 412 | Status: 413 | type: object 414 | properties: 415 | value: 416 | type: string 417 | enum: 418 | - NEW 419 | - CANCELLED 420 | - EXPIRED 421 | - PAID 422 | description: Статус 423 | date: 424 | type: string 425 | format: date-time 426 | description: Дата создания заказа 427 | 428 | ``` 429 | 430 | Неправильно 431 | ```yaml 432 | orderCreationResponse: 433 | properties: 434 | status: 435 | type: object 436 | properties: 437 | value: 438 | type: string 439 | enum: 440 | - NEW 441 | - CANCELLED 442 | - EXPIRED 443 | - PAID 444 | description: Статус 445 | date: 446 | type: string 447 | format: date-time 448 | description: Дата создания заказа 449 | orderCreationResponse: 450 | properties: 451 | status: 452 | type: object 453 | properties: 454 | value: 455 | type: string 456 | enum: 457 | - NEW 458 | - CANCELLED 459 | - EXPIRED 460 | - PAID 461 | description: Статус 462 | date: 463 | type: string 464 | format: date-time 465 | description: Дата создания заказа 466 | ``` 467 | 468 | #### Обоснование 469 | Следование принципу [DRY](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself) 470 | 471 | --- 472 | 473 | ### Используем UPPER_SNAKE_CASE для Enum и mapping для discriminator 474 | | ID | Severity | Дата принятия | 475 | |---------------------------------------|----------|---------------| 476 | | enum-discriminator-upper-snaker-case | MUST | 13.03.2025 | 477 | 478 | #### Описание правила 479 | Перечисления и значения маппинга для дискриминатора именуются UPPER_SNAKE_CASE 480 | 481 | Правильно 482 | ```yaml 483 | properties: 484 | value: 485 | type: string 486 | enum: 487 | - NEW_ORDER 488 | - CANCELLED 489 | - EXPIRED 490 | - PAID 491 | ``` 492 | Неправильно 493 | ```yaml 494 | properties: 495 | value: 496 | type: string 497 | enum: 498 | - NewOreder 499 | - expired-order 500 | - paid_order 501 | ``` 502 | 503 | #### Обоснование 504 | В большенстве ЯП константы и перечисления именуются UPPER_SNAKE_CASE, для поддержания единобразия в спецификации стоит делать так же. 505 | 506 | --- 507 | 508 | ### Пагинация 509 | 510 | #### offset-пагинация (page,size) 511 | | ID | Severity | Дата принятия | 512 | |--------------------|----------|---------------| 513 | | offset-pagination | MUST | 13.03.2025 | 514 | 515 | ##### Описание правила 516 | 517 | Пагинацию можно не использовать, если размер ответа не превышает 1Мб и количество элементов не больше 100. В ином случае, рекомендуется использовать курсор-пагинацию. 518 | 519 | При использовании пагинации приоритетным вариантом является cursor-пагинация. Так как она является устойчивой к изменению данных (что важно для клиентов, выполняющих синхронизацию данных из банка со своей системой) и более производительна для больших объемов данных. 520 | 521 | Если клиенты вашего продукта используют API не выполняя предварительное сохранение данных на своей стороне, более предпочтительной является offset-пагинация (например, напрямую выводит данные в UI). 522 | 523 | Запрос первой страницы может быть без явного указания оффсета: 524 | 525 | ``` 526 | GET /v1/documents?limit=20 527 | ``` 528 | 529 | ``` 530 | { 531 | "data": [ 532 | { 533 | "id": 124 534 | } 535 | ], 536 | "offset": 0, 537 | "limit": 20, 538 | "totalCount": 35 539 | } 540 | ``` 541 | 542 | Запрос следующей страницы со значеним оффсета: 543 | 544 | ``` 545 | GET /v1/documents?limit=20&offset=20 546 | ``` 547 | 548 | Если записей больше нет, totalCount будет меньше или равен offset + limit: 549 | 550 | ``` 551 | { 552 | "data": [ 553 | { 554 | "id": 304 555 | } 556 | ], 557 | "offset": 20, 558 | "limit": 20, 559 | "totalCount": 35 560 | } 561 | ``` 562 | 563 | --- 564 | 565 | #### cursor-пагинация 566 | | ID | Severity | Дата принятия | 567 | |--------------------|----------|---------------| 568 | | cursor-pagination | MUST | 13.03.2025 | 569 | 570 | ##### Описание правила 571 | 572 | Для больших или быстро меняющихся наборов данных, лучше использовать cursor-пагинацию. 573 | 574 | Для значения курсора следует использовать уникальный индексированный набор полей.Например, дату создания записи. 575 | 576 | Для унификации значение курсора кодируется в base64. 577 | 578 | Запрос без явного указания курсора вернет первые `n` записей по заданному порядку сортировки: 579 | ``` 580 | GET /sbp/v1/products?limit=20 581 | ``` 582 | 583 | Ответ должен содержать значение курсора начала следующей страницы: 584 | ```json 585 | { 586 | "content": [ 587 | { 588 | "id": 122 589 | } 590 | ], 591 | "nextCursor": "ewogICAgICAiaWQiOiAxMjMKfQ==" 592 | // Содержит 593 | // { 594 | // "id": 123 595 | // } 596 | } 597 | ``` 598 | 599 | Запрос следующей страницы со значеним курсора: 600 | ``` 601 | GET /sbp/v1/products?cursor=ewogICAgICAiaWQiOiAxMjMKfQ==&limit=1 602 | ``` 603 | 604 | В ответ вернет: 605 | ```json 606 | { 607 | "content": [ 608 | { 609 | "id": 123 610 | } 611 | ], 612 | "nextCursor": "ewogICAgICAiaWQiOiAxMjQKfQ==" 613 | // Содержит 614 | // { 615 | // "id": 124 616 | // } 617 | } 618 | ``` 619 | Если записей больше нет, content должен быть пустым, а nextCursor null: 620 | ```json 621 | { 622 | "content": [], 623 | "nextCursor": null 624 | } 625 | ``` 626 | 627 | При необходимости сортировки данных, их следует добавлять в курсор. 628 | Запрос: 629 | ``` 630 | GET /sbp/v1/products?sortBy=price,name&limit=20 631 | ``` 632 | Ответ: 633 | ```json 634 | { 635 | "content": [ 636 | { 637 | "id": 123, 638 | "createdAt": "2023-07-22T09:14:38+03:00" 639 | } 640 | ], 641 | "nextCursor": "ewogICJpZCI6IDEyNCwKICAiY3JlYXRlZEF0IjogIjIwMjMtMDctMjJUMTA6MTQ6MzgrMDM6MDAiCn0=" 642 | } 643 | ``` 644 | 645 | --- 646 | 647 | ### Сортировка 648 | | ID | Severity | Дата принятия | 649 | |--------------------|----------|---------------| 650 | | sorting | MUST | 13.03.2025 | 651 | 652 | 653 | #### Описание правила 654 | 655 | В общем случае, клиент не должен полагаться на сортировку результата сервером, за исключением случаев, когда документация на API явно описывает сортировку по-умолчанию. 656 | 657 | В случаях когда запрос возвращает небольшую выборку, более предпочтительным вариантом может оказаться сортировка на стороне клиента. 658 | 659 | В случаях когда запрос возвращает небольшую выборку, более предпочтительным вариантом может оказаться сортировка на стороне клиента. 660 | 661 | Если требуется сортировка по одному полю, то рекомендуем указывать поле для сортировки в параметре **sortBy** и порядок сортировки в параметре **orderBy** (asc/desc). 662 | 663 | $`\textcolor{green}{\text{Правильно:}}`$ 664 | 665 | ``` 666 | GET /api/v1/products?sortBy=price&orderBy=desc 667 | ``` 668 | 669 | $`\textcolor{red}{\text{Неправильно:}}`$ 670 | 671 | ``` 672 | GET /api/v1/users?sort=-created_at,+username 673 | 674 | GET /api/v1/products?sortby=price_asc&date_desc 675 | 676 | GET /api/v1/users?sort={"created_at":"desc","username":"asc"} 677 | ``` 678 | 679 | Если параметр **orderBy** не указан, то по-умолчанию предполагается сортировка по возрастанию (*asc*). 680 | 681 | В сложных случаях, когда требуется сортировка по нескольким полях в сочетании со сложными фильтрами и(или) пагинацией, рекомендуем использовать метод POST. 682 | 683 | $`\textcolor{green}{\text{Рекомендуем:}}`$ 684 | 685 | ``` 686 | POST /api/v1/users/search 687 | { 688 | "filter": "some filter", 689 | "paging": { 690 | "offset": 50, 691 | "limit": 20 692 | }, 693 | "order": [ 694 | { "priority": 1, 695 | "sortBy": "created_at", 696 | "orderBy": "desc" 697 | }, 698 | { "priority": 2, 699 | "sortBy": "username", 700 | "orderBy": "asc" 701 | } 702 | ] 703 | } 704 | ``` 705 | 706 | --- 707 | 708 | ### Фильтрация 709 | | ID | Severity | Дата принятия | 710 | |-------------------------|----------|---------------| 711 | | filtering | MUST | 18.03.2025 | 712 | 713 | #### Описание правила 714 | 715 | По умолчанию необходимо использовать фильтры в виде строки запроса GET 716 | 717 | $`\textcolor{green}{\text{Пример:}}`$ 718 | ``` 719 | GET /api/sbp/v1/products?name=product&price=50&category=electronics 720 | ``` 721 | 722 | В исключительных случаях, сли список аргументов в фильтре слишком длинный (URL может превысить 2048 символов), 723 | то рекомендуем использовать для реализации фильтров запрос POST с передачей аргументов в теле запроса. 724 | 725 | $`\textcolor{green}{\text{Правильно:}}`$ 726 | 727 | ``` 728 | POST /api/sbp/v1/products/search 729 | 730 | { 731 | dateFrom="...", 732 | dateTo="...", 733 | .... 734 | } 735 | ``` 736 | 737 | Нельзя передавать аргументы в теле запроса GET. 738 | 739 | $`\textcolor{red}{\text{Неправильно:}}`$ 740 | 741 | ``` 742 | GET /api/sbp/v1/products 743 | { 744 | "name": "product", 745 | "price": 50, 746 | "category": "electronics" 747 | } 748 | ``` 749 | 750 | Реализация фильтров с логическими операциями or / not / ... по усмотрению исполнителя, общая рекомендация - избегать необходимости в таких фильтрах. 751 | 752 | $`\textcolor{red}{\text{Не рекомендуем:}}`$ 753 | 754 | ``` 755 | GET /api/sbp/v1/products?or_label=A&or_label=B&label_not=C 756 | ``` 757 | 758 | --- 759 | 760 | ### Используй формат даты-времени ISO 8601 761 | | ID | Severity | Дата принятия | 762 | |--------------------------|----------|---------------| 763 | | date-time-format-iso-8601| MUST | 18.03.2025 | 764 | 765 | #### Описание правила 766 | 767 | Используем формат [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). 768 | Избегаем использования времени / микросекунд / миллисекунд если в этом нет явной необходимости. 769 | Принимаем в запросах время и в UTC, и с указанием чаcового пояса, возвращаем в ответе строго в формате UTC. Если в запросе нет признака UTC или указания часового пояса - возвращаем ошибку валидации. 770 | 771 | Паттерны для даты-времени **YYYY-MM-DDThh:mm:ssZ** / **YYYY-MM-DDThh:mm:ss±hh:mm**. 772 | 773 | Паттерн для даты **YYYY-MM-DD**. 774 | 775 | Используем названия полей вида someData как для даты, так и для даты-времени. 776 | 777 | 778 | $`\textcolor{green}{\text{Правильно:}}`$ 779 | 780 | ```json 781 | "birthDate": "1980-01-30" 782 | "qrExpirationDate": "2023-07-22T09:14:38+03:00" 783 | "createDate": "2019-08-24T14:15:22Z" 784 | "transactionDate": "2022-12-08T13:21:04.631543+03:00" 785 | ``` 786 | 787 | $`\textcolor{red}{\text{Неправильно:}}`$ 788 | 789 | ```json 790 | "birthday": "1980.01.30" 791 | "dateTime": "2020-01-15T16:01:49.043924" 792 | "createDateTime": "2011-03-01T14:15:22Z" 793 | ``` 794 | 795 | #### Обоснование 796 | 797 | ISO 8601 стандарт дефакто в отрасли. Все знают и понимают этот формат, большенство ЯП использют данный формат по умолчанию для парсинга и форматирования дат. 798 | 799 | --- 800 | 801 | ### используй формат стран ISO 3166 802 | | ID | Severity | Дата принятия | 803 | |--------------------------|----------|---------------| 804 | | country-forma-iso-3166 | MUST | 18.03.2025 | 805 | 806 | #### Описание правила 807 | Формат стран [ISO 3166, UPPER ALPHA-2](https://en.wikipedia.org/wiki/ISO_3166-1). 808 | 809 | $`\textcolor{green}{\text{Правильно:}}`$ 810 | 811 | ```json 812 | "currency": "RUB" 813 | ``` 814 | 815 | $`\textcolor{red}{\text{Неправильно:}}`$ 816 | 817 | ```json 818 | "currency": "643" 819 | "currency": "Ruble" 820 | ``` 821 | 822 | #### Обоснование 823 | 824 | ISO 3166 стандарт дефакто в отрасли. Все знают и понимают этот формат, большенство ЯП использют данный формат по умолчанию для парсинга и форматирования дат. 825 | 826 | --- 827 | 828 | ### используй формат стран ISO 4217 829 | | ID | Severity | Дата принятия | 830 | |--------------------------|----------|---------------| 831 | | currency-format-iso-4217 | MUST | 18.03.2025 | 832 | 833 | #### Описание правила 834 | Формат валют [ISO 4217, UPPER ALPHA-3](https://en.wikipedia.org/wiki/ISO_4217). 835 | 836 | Суммы указываются как строка с дробным числом (если количество разрядов >0 ), разделитель точка, количество разрядов зависит от валюты. 837 | 838 | Необходимо всегда указывать код валюты. 839 | 840 | 841 | $`\textcolor{green}{\text{Правильно:}}`$ 842 | 843 | ```json 844 | "currency": "RUB" 845 | "amount": 1110.11 846 | ``` 847 | 848 | $`\textcolor{red}{\text{Неправильно:}}`$ 849 | 850 | ```json 851 | "currency": "643" 852 | "currency": "Ruble" 853 | "sum": 1200,1 854 | ``` 855 | 856 | #### Обоснование 857 | 858 | ISO 4217 стандарт дефакто в отрасли. Все знают и понимают этот формат, большенство ЯП использют данный формат по умолчанию для парсинга и форматирования дат. 859 | 860 | --- 861 | 862 | ### Используй версионирование в URL 863 | | ID | Severity | Дата принятия | 864 | |-------------------------|----------|---------------| 865 | | url-versioning | MUST | 12.03.2025 | 866 | 867 | 868 | #### Описание правила 869 | 870 | Единственным способом для версионирования API является версионирование в URL. Версия должна быть указана в пути запроса, в начале метода, в формате `/beta`, `/v1`, `/v2` и т.д. 871 | 872 | API в статусе beta могут быть изменены без обратной совместимости без уведомления. 873 | ``` 874 | /v1/payment-orders/{id} 875 | ``` 876 | 877 | Версия указывается в начале каждого метода API. TBD ссылка 878 | 879 | 880 | ```yaml 881 | paths: 882 | /beta/payment-orders/{id}: 883 | post: 884 | ... 885 | /v1/payment-orders/{id}: 886 | post: 887 | ... 888 | 889 | ``` 890 | 891 | 892 | Версионирование распространяется на отдельный метод API, а не на весь API целиком. На усмотрение владельца API можно версионировать весь API целиком, это не нарушает требования к версионированию. 893 | 894 | Так как присвоение номера версии API накладывает строгие правила для обратной совместимости, для новых или экспериментальных API можно использовать версию /beta, которая позволяет изменять контракт API без обратной совместимости. Потребители таких API берут на себя риски ломающих изменений и учитывают это при использовании таких API. 895 | За исключением обратной совместимости все правила этого гайда равнозначно применяются к API с версиями `/beta`. 896 | 897 | Рекомендуется ограничивать время существования `/beta` версии в эксплуатации и либо назначать API версию, либо выводить из эксплуатации. Рекомендуемый срок эксплуатации таких API - 1 месяц 898 | 899 | ```yaml 900 | paths: 901 | /beta/payment-orders/{id}: 902 | post: 903 | ... 904 | /v1/payment-orders/{id}: 905 | post: 906 | ... 907 | /v2/payment-orders: 908 | get: 909 | ... 910 | ``` 911 | 912 | 913 | Правильно: 914 | 915 | ```json 916 | /beta/statements 917 | /v1/statements 918 | /v2/payment-orders/ 919 | ``` 920 | 921 | Неправильно: 922 | ``` 923 | /statements/v1 924 | /payment-orders/v2/ 925 | /v1.0/statements 926 | /payment-orders/2.0/ 927 | 928 | /statements?version=1.0 929 | 930 | 931 | ``` 932 | 933 | 934 | #### Обоснование 935 | 936 | Версионирование API в пути запроса обеспечивает ясность и простоту управления различными версиями API. Использование формата `/v1`, `/v2` и т.д. является стандартным и широко признанным подходом, который упрощает понимание и поддержку API. 937 | 938 | Мы оставляем за собой большую гибкость, распространяя версию не на весь API, а на отдельный метод API. Это позволяет обновлять версию независимо для каждого метода. 939 | Важно, если вы понимаете, что обновление версии ведет к обратно несовместимым изменениям в рамках вашего API(набора методов), вы должны предусмотреть обновление версии связанных методов одновременно. 940 | 941 | --- 942 | 943 | ### Учитывай обратную совместимость API 944 | | ID | Severity | Дата принятия | 945 | |-----------------------------------|----------|---------------| 946 | | versioning-backward-compatibility | MUST | 12.03.2025 | 947 | 948 | 949 | #### Описание правила 950 | 951 | 952 | Изменяйте API, но сохраняйте работоспособность для всех потребителей. Потребители обычно имеют независимые релизный циклы, сосредоточены на стабильности и избегают изменений своих интеграций, которые не приносят дополнительной пользы. API - это контракт между поставщиками и потребителями услуг, который нельзя нарушить односторонними решениями. Иключение `/beta` версия, в рамках которой могут быть любые ломающие изменения, в любой момент времени 953 | 954 | Есть 2 способа изменения API с учетом обратной совместимости: 955 | 956 | - Следовать правилам обратно совместимых изменений 957 | - Выпускать новую версию метода API или API целиком 958 | 959 | В REST API изменения могут быть ломающими (breaking changes) или обратно-совместимыми (backward-compatible changes) в зависимости от того, будут ли они нарушать существующий контракт API: 960 | 961 | - Ломающие изменения - нарушают контракт API и могут привести к тому, что клиенты, которые ранее работали с API, перестанут работать или будут работать некорректно. Например, если изменить тип возвращаемого значения метода API, это может привести к ошибке на стороне клиента, который ожидал другой тип данных. 962 | - Обратно-совместимые изменения - не нарушают контракт API и не приводят к сбоям на стороне клиента. Такие изменения могут включать добавление новых ресурсов, методов, параметров запросов, но не изменение или удаление существующих. 963 | 964 | Допустимые обратно-совместимые изменения: 965 | 966 | - Добавление новых ресурсов или методов 967 | - Добавление необязательных параметров/полей в запрос/ответ 968 | - Добавление новых заголовков в ответе 969 | - Изменение порядка полей в ответе 970 | 971 | Запрещенные ломающие изменения в рамках одной версии(кроме версии `/beta`): 972 | 973 | - Изменение в стандартных или кастомных заголовках ответа 974 | - Изменение бизнес-логики методов (например, в документации описано поведение метода, но внезапно метод возвращает другой результат при неизменных входных данных) 975 | - Изменение типов данных параметров или полей в ответе 976 | - Удаление или переименование ресурсов, методов или полей 977 | - Изменение регистра значений в ответе (например, "OK" вместо "ok") 978 | - Изменение порядка или добавление/удаление/изменение элементов в перечислениях (enum) 979 | - Добавление обязательных параметров/заголовков/полей в запрос 980 | - Изменение порядка сортировки по умолчанию в ответе 981 | 982 | Важно помнить, что любые изменения в API должны быть хорошо продуманы и документированны, чтобы избежать проблем совместимости и сбоев у потребителей API. 983 | 984 | 985 | Правильно: 986 | ```json 987 | # Добавление необязательного поля в ответ 988 | # /v1(исходный): 989 | { 990 | "id": 123, 991 | "name": "Product" 992 | } 993 | 994 | # /v1(обновленный): 995 | { 996 | "id": 123, 997 | "name": "Product", 998 | "description": "Optional description" 999 | } 1000 | 1001 | ``` 1002 | Неправильно: 1003 | ```json 1004 | # Изменение типа данных существующего поля 1005 | # /v1(исходный): 1006 | { 1007 | "id": 123, 1008 | "quantity": 5 1009 | } 1010 | 1011 | # /v1(обновленный): 1012 | { 1013 | "id": 123, 1014 | "quantity": "5" 1015 | } 1016 | 1017 | ``` 1018 | 1019 | #### Обоснование 1020 | 1021 | Обратная совместимость критически важна для сохранения доверия клиентов к API. Нарушение обратной совместимости может привести к сбоям в работе клиентских приложений, что влечет за собой потерю доверия к сервису и дополнительные затраты на поддержку. 1022 | Соблюдая требования к обратной совместимости, мы стремимся: 1023 | - Поддерживать существующих клиентов без изменения их кода 1024 | - Внедрять новые функции, не затрагивая работу текущих клиентов 1025 | - Предоставлять достаточное время для миграции клиентов на новые версии API 1026 | 1027 | --- 1028 | 1029 | 1030 | 1031 | ### Соблюдайте сигнатуру пути API 1032 | | ID | Severity | Дата принятия | 1033 | |-------------------------|----------|---------------| 1034 | | use-correct-url-sequence | MUST | 12.03.2025 | 1035 | 1036 | 1037 | #### Описание правила 1038 | 1039 | Структура URL API должна соответствовать следующему формату: 1040 | 1041 | Внутренний API: 1042 | - `{поддомен}.raiffeisen.ru/v{номер версии}/{путь}` 1043 | - `{поддомен}.raiffeisen.ru/{префикс сервиса}/v{номер версии}/{путь}` 1044 | 1045 | > Методы в контракте OpenAPI всегда начинаются с номера версии - `/v1/...`. Все префиксы "слева" от версии, должны быть скрыты на gateway. Это позволяет минимизировать изменение контракта при публикации API на разные gateway. 1046 | 1047 | Внешний API (публичный): 1048 | - `{поддомен}.raiffeisen.ru/{префикс продукта}/v{номер версии}/{путь}` 1049 | - `{поддомен}.raif.ru/{префикс продукта}/v1/{путь}` 1050 | 1051 | Где: 1052 | - `{поддомен}` - если есть, может быть любой на усмотрение команды, в формате kebab-case. См. [Использование kebab-case для пути](#использование-kebab-case-для-пути) 1053 | - `{префикс продукта/сервиса}` - является частью URL gateway на котором размещен API. В случае с внешним API это может быть префикс продукта, чтобы разделить API разных продуктов на одном gateway. В случае с внутренним API это может быть префиксом сервиса, чтобы разделить API разных сервисов на одном gateway. На внешнем gateway где потребителям являются клиенты, не стоит в качестве префикса название сервиса, так как это не имеет смысла для клиентов, рекомендуется выбирать нейминг опираясь на продукты, а не внутренние сервисы. При выборе префикса, думайте кто ваш потребитель и какую смысловую нагрузку несет для него этот префикс. См. [Избегать избыточных префиксов в пути](#избегать-избыточных-префиксов-в-пути). 1054 | - `{номер версии}` - версия API в формате `v1`, `v2`. См. [Используй версионирование в URL](#используй-версионирование-в-url) 1055 | - `{путь}` - путь к ресурсу в формате kebab-case. См. [Использование kebab-case для пути](#использование-kebab-case-для-пути) 1056 | 1057 | 1058 | > В случае использования префикса продукта/сервиса избегайте использования таких же наименований в контракте методов API. Например, если в контракте метода API есть `statements`, то в префиксе и поддомене финального URL наименование `statements` не должно поворяться. 1059 | 1060 | ✅ Правильно (внутренний API): 1061 | - `fxo.raiffeisen.ru/api/` 1062 | - `rbp-organization-service.k8s.sme.raiffeisen.ru/v1/..` 1063 | - `uno.app.lb.k8s-p-extapp-cc-01.k8s.raiffeisen.ru/api/v1/contracts` 1064 | - `cards.raiffeisen.com/v1/statements` 1065 | - `accounts.raiffeisen.com/v1/balance` 1066 | 1067 | 1068 | ✅ Правильно (внешний API): 1069 | - `api.raiffeisen.ru/fx/v1/trades/digest` 1070 | - `api.raiffeisen.ru/corp-cards/v1/statements` 1071 | 1072 | ❌ Неправильно: 1073 | - `cards.raiffeisen.com/v1/api/statements` Избыточный префикс `api` 1074 | - `payments.raiffeisen.com/v1/payments/transfers` Дублирование названия продукта в поддомене и префиксе 1075 | - `accounts.raiffeisen.com/accounts/balance/v1` Версия не в начале пути, дублирование поддомена и префикса 1076 | - `api.raiffeisen.ru/statements-service/v1/intraday` Префикс внутреннего продукта просочился на внешний gateway 1077 | 1078 | 1079 | #### Обоснование 1080 | 1081 | Такая структура обеспечивает: 1082 | - Единообразие формирование URL API по всему банку 1083 | - Прозрачное версионирование 1084 | - Чёткое разделение между продуктами/сервисами на gateway 1085 | - Быстрый переход API от внутреннего к внешнему 1086 | - Простоту в маршрутизации запросов к существующим продуктам 1087 | - Наличие версии в начале пути позволяет легко определить версию API и маршрутизировать запросы к соответствующей реализации 1088 | 1089 | --- 1090 | 1091 | ### Используй HTTP методы правильно 1092 | | ID | Severity | Дата принятия | 1093 | |-------------------------------|--------------------|---------------| 1094 | | use-correct-http-methods | MUST | 24.03.2025 | 1095 | 1096 | 1097 | #### Описание правила 1098 | 1099 | **GET** - используется только для получения данных от сервера, не изменяет данные на сервере и не должен иметь тела запроса. 1100 | 1101 | **POST** - используется для создания новых ресурсов ([см другие варианты использования](#фильтрация)), генерация идентификатора нового ресурса выполняется на стороне сервера. В общем случае **POST** не гарантирует [идемпотентность](https://en.wikipedia.org/wiki/Idempotence). Может использоваться как workaround при получении данных, в случаях когда использование GET не представляется возможным, в таком случае необходимо указывать что **POST** не создает новые сущности, а используется исключительно для получения данных. 1102 | 1103 | **PUT, PATCH** - используются для изменения существующего ресурса на стороне сервера, **PUT** полностью замещает старую сущность и при его использовании в теле запроса нужно передавать все поля сущности, **PATCH** выполняет частичное изменение, при его использовании в теле запроса достаточно передать изменяемые поля. 1104 | 1105 | **DELETE** - удаляет ресурс на стороне сервера. 1106 | 1107 | 1108 | #### GET - для получения данных 1109 | ✅ Правильно: 1110 | - `/v1/accounts/{accountId}` - получение информации о конкретном счете 1111 | - `/v1/transactions?accountId=123&fromDate=2025-01-01` - получение списка транзакций по фильтрам 1112 | - `/v1/customers/{customerId}/cards` - получение списка карт клиента 1113 | - `/v1/exchange-rates/USD/RUB` - получение текущего курса валют 1114 | 1115 | ❌ Неправильно: 1116 | - `/v1/accounts/create` - создание нового счета через GET 1117 | - `/v1/transactions/filter` - использование GET с телом запроса для фильтрации 1118 | - `/v1/logout` - выход из системы через GET (изменяет состояние) 1119 | - `/v1/cards/block?cardId=456` - блокировка карты через GET 1120 | 1121 | #### POST - для создания ресурсов 1122 | ✅ Правильно: 1123 | - `/v1/accounts` - создание нового банковского счета 1124 | - `/v1/transfers` - выполнение денежного перевода 1125 | - `/v1/customers/{customerId}/cards` - выпуск новой карты 1126 | 1127 | ❌ Неправильно: 1128 | - `/v1/accounts/{accountId}` - получение данных о счете через POST 1129 | - `/v1/accounts/{accountId}/edit` - редактирование счета через POST (нужно использовать PUT/PATCH) 1130 | - `/v1/transfers/123/delete` - удаление перевода через POST 1131 | - `/v1/accounts/search` - поиск счетов через POST (лучше GET с параметрами) 1132 | 1133 | #### PUT - для полного обновления ресурса 1134 | ✅ Правильно: 1135 | - `/v1/customers/{customerId}` - полное обновление профиля клиента 1136 | - `/v1/accounts/{accountId}/settings` - замена всех настроек счета 1137 | - `/v1/cards/{cardId}` - полное обновление информации о карте 1138 | - `/v1/credit-programs/{programId}` - обновление всех параметров кредитной программы 1139 | 1140 | ❌ Неправильно: 1141 | - `/v1/customers/{customerId}/update` - лишнее действие в URL 1142 | - `/v1/accounts` - обновление без указания идентификатора 1143 | - `/v1/cards/{cardId}/status` - частичное обновление (использовать PATCH) 1144 | - `/v1/customers/new` - создание нового клиента через PUT 1145 | 1146 | #### PATCH - для частичного обновления 1147 | ✅ Правильно: 1148 | - `/v1/accounts/{accountId}` - обновление отдельных полей счета 1149 | - `/v1/cards/{cardId}/status` - изменение статуса карты 1150 | - `/v1/customers/{customerId}/address` - обновление только адреса клиента 1151 | - `/v1/loan/{loanId}/schedule` - корректировка графика платежей по кредиту 1152 | 1153 | ❌ Неправильно: 1154 | - `/v1/accounts/{accountId}/change-status` - лишнее действие в URL 1155 | - `/v1/cards/all` - массовое обновление без указания конкретного ресурса 1156 | - `/v1/customers/{customerId}/delete-data` - удаление данных через PATCH 1157 | - `/v1/accounts/{accountId}/full-update` - полное обновление через PATCH 1158 | 1159 | #### DELETE - для удаления ресурсов 1160 | ✅ Правильно: 1161 | - `/v1/accounts/{accountId}` - закрытие/удаление счета 1162 | - `/v1/customers/{customerId}/consents/{consentId}` - отзыв согласия на обработку данных 1163 | - `/v1/cards/{cardId}` - удаление карты 1164 | - `/v1/scheduled-payments/{paymentId}` - отмена запланированного платежа 1165 | 1166 | ❌ Неправильно: 1167 | - `/v1/accounts/close` - действие без идентификатора ресурса 1168 | - `/v1/cards/{cardId}/block` - блокировка карты через DELETE (использовать PATCH) 1169 | - `/v1/authentication/logout` - выход из системы через DELETE 1170 | - `/v1/transactions/{transactionId}/refund` - возврат транзакции через DELETE 1171 | 1172 | #### Обоснование 1173 | 1174 | Правильное использование HTTP методов критически важно для создания интуитивно понятных, предсказуемых и соответствующих стандартам REST API. В финансовой среде, где безопасность и надежность имеют первостепенное значение, следование этим правилам особенно важно по следующим причинам: 1175 | 1. Семантическая ясность - Каждый метод HTTP имеет четко определенное назначение, что делает API интуитивно понятным для разработчиков. Правильное использование методов автоматически документирует предназначение эндпоинта. 1176 | 2. Безопасность системы - Методы GET предполагаются безопасными и не должны изменять состояние системы. Это критично для предотвращения непреднамеренных изменений в банковских системах через такие операции как кеширование или индексация. 1177 | 3. Идемпотентность операций - GET, PUT и DELETE должны быть идемпотентными (многократное выполнение дает тот же результат), что особенно важно при повторных запросах или восстановлении после сбоев. 1178 | 4. Правильное кеширование - Корректное использование методов позволяет промежуточным системам (прокси, CDN) правильно кешировать ответы, что улучшает производительность и снижает нагрузку. 1179 | 5. Совместимость с инструментами и фреймворками - Стандартные инструменты разработки и тестирования ожидают соответствия HTTP методов их стандартному назначению. 1180 | 1181 | Неправильное использование HTTP методов может привести к: 1182 | - Непредсказуемому поведению кеширующих систем 1183 | - Проблемам безопасности (например, изменение данных через GET-запросы) 1184 | - Затруднениям при отладке и тестировании 1185 | - Несовместимости с API-шлюзами и средствами защиты 1186 | - Нарушению пользовательского опыта для потребителей API 1187 | - Техническому долгу и сложностям при масштабировании системы 1188 | Соблюдение этого правила является фундаментальным для создания надежного, безопасного и легко сопровождаемого API. 1189 | 1190 | ### API для скачивания файлов обязано поддерживать HEAD запрос 1191 | | ID | Severity | Дата принятия | 1192 | |---------------------|----------------|---------------| 1193 | | provide-head-method | RECOMMENDATION | 07.04.2025 | 1194 | 1195 | #### Описание правила 1196 | 1197 | API для скачивания какого-либо файла должно поддерживать метод **HEAD** 1198 | 1199 | #### Обоснование 1200 | **HEAD** - запрашивает заголовки, идентичные тем, что возвращаются, если указанный ресурс будет запрошен с помощью HTTP-метода GET. Запрос может быть выполнен перед загрузкой ресурса, например, для кэширования, по заголовкам `ETag` или `Last-Modified`, или узнать размер файла без скачивания по заголовку `Content-Length` 1201 | 1202 | --- 1203 | ### Заполняй примеры в документации 1204 | | ID | Severity | Дата принятия | 1205 | |-------------------------------|--------------------|---------------| 1206 | | valid-schema-example | MUST | 24.03.2025 | 1207 | 1208 | 1209 | #### Описание правила 1210 | 1211 | [Примеры](https://swagger.io/docs/specification/adding-examples/) очень важны. Когда формируется OpenAPI спецификация, необходимо для каждого запроса/ответа операции определить примеры. То же самое применимо для опеределений указанных в ссылках, например компонентах. 1212 | 1213 | [Примеры](https://swagger.io/docs/specification/adding-examples/) помогают потребителю вашего API понять, как должны выглядеть реальные данные, когда мы отправляем запрос или получаем ответ. 1214 | Хорошие примеры очень ценны, когда данные сложные, вложенные или содержат специальное форматирование. 1215 | 1216 | Примеры должны быть в: 1217 | - Запросах операций 1218 | - Ответах операций 1219 | - Параметрах операций 1220 | - Глобальных компонентах 1221 | - Глобальных параметрах 1222 | 1223 | В версии OpenAPI 3.0, нужно включать примеры для каждого [RequestBody](https://swagger.io/docs/specification/describing-request-body/). Также нужно добавлять примеры для [Responses](https://swagger.io/docs/specification/describing-responses/), [Components](https://swagger.io/docs/specification/components/) или [Parameters](hhttps://swagger.io/docs/specification/describing-parameters/). 1224 | 1225 | ✅ Правильно: 1226 | ```yaml 1227 | paths: 1228 | /v1/accounts/{accountId}: 1229 | get: 1230 | operationId: getAccount 1231 | summary: Получение информации о счете 1232 | parameters: 1233 | - name: accountId 1234 | in: path 1235 | required: true 1236 | schema: 1237 | type: string 1238 | examples: 1239 | primaryAccount: 1240 | summary: Пример ID основного счета 1241 | value: '40817810099910004312' 1242 | cardAccount: 1243 | summary: Пример ID карточного счета 1244 | value: '40817810099910004333' 1245 | responses: 1246 | '200': 1247 | description: Информация о счете успешно получена 1248 | content: 1249 | application/json: 1250 | schema: 1251 | $ref: '#/components/schemas/Account' 1252 | examples: 1253 | savingsAccount: 1254 | summary: Пример сберегательного счета 1255 | value: 1256 | accountId: '40817810099910004312' 1257 | type: 'savings' 1258 | currency: 'RUB' 1259 | balance: 150000.00 1260 | status: 'active' 1261 | openDate: '2023-05-15' 1262 | interestRate: 5.5 1263 | cardAccount: 1264 | summary: Пример дебетового карточного счета 1265 | value: 1266 | accountId: '40817810099910004333' 1267 | type: 'debit' 1268 | currency: 'RUB' 1269 | balance: 75430.25 1270 | status: 'active' 1271 | openDate: '2022-11-03' 1272 | cards: [ 1273 | { 1274 | cardId: '5469440012345678', 1275 | expiryDate: '02/26', 1276 | status: 'active' 1277 | } 1278 | ] 1279 | 1280 | /v1/transfers: 1281 | post: 1282 | operationId: createTransfer 1283 | summary: Выполнение денежного перевода 1284 | requestBody: 1285 | required: true 1286 | content: 1287 | application/json: 1288 | schema: 1289 | $ref: '#/components/schemas/TransferRequest' 1290 | examples: 1291 | domesticTransfer: 1292 | summary: Пример внутреннего перевода 1293 | value: 1294 | sourceAccountId: '40817810099910004312' 1295 | destinationAccountId: '40817810099910004333' 1296 | amount: 15000.00 1297 | currency: 'RUB' 1298 | description: 'Перевод на карту' 1299 | swiftTransfer: 1300 | summary: Пример международного SWIFT-перевода 1301 | value: 1302 | sourceAccountId: '40817810099910004312' 1303 | destinationBIC: 'CHASUS33' 1304 | destinationAccountId: '36003588120300' 1305 | amount: 1000.00 1306 | currency: 'USD' 1307 | description: 'Payment for services' 1308 | recipientName: 'John Smith' 1309 | recipientAddress: '123 Main St, New York, USA' 1310 | responses: 1311 | '201': 1312 | description: Перевод успешно создан 1313 | content: 1314 | application/json: 1315 | schema: 1316 | $ref: '#/components/schemas/TransferResponse' 1317 | examples: 1318 | successfulTransfer: 1319 | summary: Пример успешного перевода 1320 | value: 1321 | transferId: 'TRF-2025-03-24-123456' 1322 | status: 'completed' 1323 | timestamp: '2025-03-24T14:30:45Z' 1324 | fee: 0.00 1325 | pendingTransfer: 1326 | summary: Пример перевода на обработке 1327 | value: 1328 | transferId: 'TRF-2025-03-24-123457' 1329 | status: 'pending' 1330 | timestamp: '2025-03-24T14:35:22Z' 1331 | estimatedCompletionTime: '2025-03-24T15:00:00Z' 1332 | fee: 150.00 1333 | 1334 | components: 1335 | schemas: 1336 | Account: 1337 | type: object 1338 | properties: 1339 | accountId: 1340 | type: string 1341 | example: '40817810099910004312' 1342 | type: 1343 | type: string 1344 | enum: [savings, checking, credit, debit] 1345 | example: 'savings' 1346 | currency: 1347 | type: string 1348 | example: 'RUB' 1349 | balance: 1350 | type: number 1351 | format: double 1352 | example: 150000.00 1353 | status: 1354 | type: string 1355 | enum: [active, blocked, closed] 1356 | example: 'active' 1357 | openDate: 1358 | type: string 1359 | format: date 1360 | example: '2023-05-15' 1361 | required: 1362 | - accountId 1363 | - type 1364 | - currency 1365 | - balance 1366 | - status 1367 | 1368 | parameters: 1369 | DateRangeFrom: 1370 | name: fromDate 1371 | in: query 1372 | description: Начало периода для выборки данных 1373 | schema: 1374 | type: string 1375 | format: date 1376 | examples: 1377 | lastMonth: 1378 | summary: Пример начала прошлого месяца 1379 | value: '2025-02-01' 1380 | currentYear: 1381 | summary: Пример начала текущего года 1382 | value: '2025-01-01' 1383 | ``` 1384 | ❌ Неправильно: 1385 | 1386 | ```yaml 1387 | paths: 1388 | /v1/accounts/{accountId}: 1389 | get: 1390 | operationId: getAccount 1391 | summary: Получение информации о счете 1392 | parameters: 1393 | - name: accountId 1394 | in: path 1395 | required: true 1396 | schema: 1397 | type: string 1398 | # Отсутствуют примеры параметра 1399 | responses: 1400 | '200': 1401 | description: Информация о счете успешно получена 1402 | content: 1403 | application/json: 1404 | schema: 1405 | $ref: '#/components/schemas/Account' 1406 | # Отсутствуют примеры ответа 1407 | 1408 | /v1/transfers: 1409 | post: 1410 | operationId: createTransfer 1411 | summary: Выполнение денежного перевода 1412 | requestBody: 1413 | required: true 1414 | content: 1415 | application/json: 1416 | schema: 1417 | $ref: '#/components/schemas/TransferRequest' 1418 | # Отсутствуют примеры запроса 1419 | responses: 1420 | '201': 1421 | description: Перевод успешно создан 1422 | content: 1423 | application/json: 1424 | schema: 1425 | $ref: '#/components/schemas/TransferResponse' 1426 | # Отсутствуют примеры ответа 1427 | 1428 | components: 1429 | schemas: 1430 | Account: 1431 | type: object 1432 | properties: 1433 | accountId: 1434 | type: string 1435 | # Отсутствует пример поля 1436 | type: 1437 | type: string 1438 | enum: [savings, checking, credit, debit] 1439 | # Отсутствует пример поля 1440 | # Остальные поля также без примеров 1441 | 1442 | ``` 1443 | 1444 | 1445 | #### Обоснование 1446 | 1447 | Пользователь начинает свое взаимодействие с API с контракта. Хорошо задокументированный контракт, позволяет быстрее интегрироваться с вашим API. Независимо от того, для каких целей вы делаете API, API First предполагает, что вы начинаете разработку вашего API именно с контракта и сразу можете заложить необходимую документацию. 1448 | 1449 | При отсутствии документации, ваш контракт потребуется дорабатывать в момент публикации на клиентов/пользователей, поэтому рекомендуется закладывать документацию на самых ранних этапах создания спецификации. 1450 | 1451 | 1452 | --- 1453 | ### Не используй статусы перенаправления запроса 1454 | | ID | Severity | Дата принятия | 1455 | |-------------------------------|--------------------|---------------| 1456 | | not-use-redirection-codes | RECOMMENDATION | 24.03.2025 | 1457 | 1458 | #### Описание правила 1459 | 1460 | Не используй коды редиректа для API(кроме **304**, который безопасен и на самом деле не redirect код). Обычно коды редиректа используются, чтобы перенаправить запрос клиента в новое место, где развернут ваш сервис. Тем не менее, это лучше решается одним из следующих способов: 1461 | 1462 | - Изменить клиентов, дав им возможность мигрировать на новый адрес, при этом избегая необходимость редиректов. 1463 | - Перенаправлять трафик на сетевом уровне(gateway, reverse proxy), без необходимости вовлекать клиента. 1464 | - Deprecation эндпоинта и вывод из эксплуатации 1465 | 1466 | 1467 | #### Обоснование 1468 | 1469 | Так как существуют более надежные решения для миграции потребителей на другой адрес, следует избегать применения redirect кодов. 1470 | Есть еще ряд причин почему не стоит использовать redirect коды: 1471 | - Клиенты API `!=` Браузер - браузеры автоматически следуют редиректам, а backend-клиенты(мобильные приложения, сервисы) - нет. 1472 | - Проблемы с аутентификацией(OAuth, JWT, API-ключи) - при редиректах если клиент не передаст авторизационный токен в новый URL -> запрос сломается 1473 | - Неожиданные проблемы с HTTP-методами - **301**, **302** могут не сохранаять HTTP-метод(`POST`->`GET`). **307**, **308** сохраняют метод, но **клиенты API не всегда их поддерживают**. Следовательно ломается логика API 1474 | - Разные библиотеки по-разному работают с редиректами - curl(по умолчанию не следует редиректам на POST), Java HttpClient(может терять заголовки), Python reqeuest(меняет `POST` на `GET` при 301/302) 1475 | 1476 | 1477 | --- 1478 | ### Используй только наиболее распространенные коды состояния HTTP 1479 | | ID | Severity | Дата принятия | 1480 | |-------------------------------|--------------------|---------------| 1481 | | use-most-common-http-codes | RECOMMENDATION | 25.03.2025 | 1482 | 1483 | 1484 | #### Описание правила 1485 | 1486 | Наиболее часто используемые коды являются более понятными и перечислены ниже как подмножество официальных кодов состояния HTTP и при этом соответствуют их семантике в RFC. 1487 | Мы избегаем менее часто используемых кодов, которые легко могут вызвать неверные представления из-за менее знакомой семантики и специфических интерпретаций API. 1488 | 1489 | #### Легенда 1490 | 1491 | ✅ Используй 1492 | 1493 | Общий, хорошо понятный код состояния, который следует использовать там, где это необходимо. Это НЕ означает, что каждая операция должна возвращать этот код. 1494 | 1495 | ❌ Не используй 1496 | 1497 | Мы не видим подходящего случая для возврата этого кода состояния из RESTful API. Код состояния может быть применим в других контекстах, например, возвращаться обратными прокси-серверами, для веб-страниц и т. д. Неявно также означает ⚠️ Не документируй, поскольку коды состояния, которые не возвращаются API, также не должны документироваться. 1498 | 1499 | ✅ Документируй 1500 | 1501 | Если код состояния может быть возвращен API, он должен быть задокументирован в спецификации API. 1502 | 1503 | ⚠️ Не документируй 1504 | 1505 | Код статуса имеет хорошо понятное стандартное значение, поэтому документируйте его только в том случае, если вы хотите добавить какие-то специфические детали. 1506 | 1507 | #### Успешные коды 1508 | 1509 | ##### 200 OK 1510 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-200-ok) ✅ Используй ✅ Документируй `` 1511 | 1512 | Это наиболее общий ответ на успешное выполнение запроса. Его следует использовать, если более конкретные коды ниже неприменимы. 1513 | 1514 | ##### 201 Created 1515 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-201-created) ✅ Используй ✅ Документируй `POST`, `PUT` 1516 | 1517 | Возвращается при успешном создании ресурса. **201** возвращается как с телом ответа, так и без него (в отличие от **200** / **204**). 1518 | 1519 | ##### 202 Accepted 1520 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-202-accepted) ✅ Используй ✅ Документируй `POST`, `PUT`, `PATCH`, `DELETE` 1521 | 1522 | Запрос был успешным и будет обработан асинхронно. Применяется только к методам, которые что-то изменяют. 1523 | 1524 | ##### 204 No content 1525 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-204-no-content) ✅ Используй ✅ Документируй `POST`, `PUT`, `PATCH`, `DELETE` 1526 | 1527 | Возвращается вместо 200, если нет тела ответа. Обычно применяется только для методов, которые что-то изменяют. 1528 | 1529 | ##### 205 Reset Content 1530 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-205-reset-content) ❌ Не используй `` 1531 | 1532 | Это предназначено для интерактивных случаев использования, например, для очистки формы после ее отправки. Нет никаких причин использовать его в REST API. 1533 | 1534 | ##### 206 Partial Content 1535 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-206-partial-content) ❌ Не используй `` 1536 | 1537 | Для ответов на запросы диапазона, когда возвращается только часть ресурса, указанная диапазоном байтов. Это не относится к пагинации, где следует использовать обычный 200. Этот статус полезен для API, которые работают с файлами и потоковыми данными, но не нужен для обычных REST API. 1538 | 1539 | ##### 207 Multi-Status 1540 | [RFC](https://datatracker.ietf.org/doc/html/rfc4918#section-11.1) ❌ Не используй `` 1541 | 1542 | Возвращается когда один запрос затрагивает **несколько ресурсов**, и для каждого из них необходимо вернуть **разный статус выполнения**. Не рекомендуем использовать этот код ответа, так как изнчально он является расширением из WebDAV архитектуры, которая плохо ложится на традиционный REST API. При использовании статуса **207** важно контроллировать потребителя, потому что такой статус создает сложность при обработке ошибок. 1543 | Для batch-загрузки лучше использовать [200 OK](#200-ok) статус с массивом результатов для каждого объекта. 1544 | 1545 | #### Перенаправление(redirect) 1546 | 1547 | ##### 301 Moved Permanently 1548 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-301-moved-permanently) ❌ Не используй `` 1549 | 1550 | Этот и все последующие запросы должны быть направлены на указанный URI. См. [Не используй статусы перенаправления запроса](#не-используй-статусы-перенаправления-запроса) 1551 | 1552 | ##### 302 Found 1553 | [RFC](https://tools.ietf.org/html/rfc9110#name-302-found) ❌ Не используй `` 1554 | 1555 | Это временное перенаправление, при котором некоторые http клиенты могут изменить метод запроса с `POST` на `GET`. В основном используется для перенаправления отправленных форм в браузерах. См. [Не используй статусы перенаправления запроса](#не-используй-статусы-перенаправления-запроса) 1556 | 1557 | ##### 303 See Other 1558 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-303-see-other) ❌ Не используй `POST`, `PUT`, `PATCH`, `DELETE` 1559 | 1560 | Ответ на запрос может быть найден по другому URI с использованием метода GET. Альтернативная версия **302** для случая, когда клиент должен изменить метод на GET. См. [Не используй статусы перенаправления запроса](#не-используй-статусы-перенаправления-запроса) 1561 | 1562 | ##### 304 Not Modified 1563 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-304-not-modified) ✅ Документируй `GET`, `HEAD` 1564 | 1565 | Это специальный HTTP-код, который означает, что **ресурс не изменился с момента последнего запроса клиента**. Этот статус используется **только с кешированными данными.**. Когда клиент запрашивает ресурс, он может отправить заголовки `If-Modified-Since` или `If-None-Match`, указывающие на то, что у него уже есть кешированная версия. Если сервер видит, что ресурс **не изменился** jy djpdhfoftn **304 Not Modified**, а клиент использует свою кешированную версию. Для запросов `PUT`, `PATCH`, `DELETE` вместо этого используйте **412** статус ответа. 1566 | 1567 | 1568 | ##### 307 Temporary Redirect 1569 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-307-temporary-redirect) ❌ Не используй `` 1570 | 1571 | Ответ на запрос может быть найден по другому URI. Альтернативная версия **302**, в которой клиент должен сохранить тот же метод, что и в исходном запросе. См. [Не используй статусы перенаправления запроса] 1572 | 1573 | ##### 308 Permanent Redirect 1574 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-308-permanent-redirect) ❌ Не используй `` 1575 | 1576 | Аналогично **307**, но клиент должен навсегда сохранить новый URI. Применимо скорее к браузерам. См. [Не используй статусы перенаправления запроса] 1577 | 1578 | #### Ошибки клиента 1579 | 1580 | ##### 400 Bad Request 1581 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-400-bad-request) ✅ Используй ✅ Документируй `` 1582 | 1583 | Неспецифическая ошибка клиента, указывающая на то, что сервер не может обработать запрос из-за чего-то, что воспринимается как ошибка клиента (например, неправильный синтаксис запроса, не валидный запрос). Должна также передаваться в случае, если тело запроса не прошло проверку бизнес-логики / семантики (вместо использования **422**). 1584 | 1585 | ##### 401 Unauthorized 1586 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized) ✅ Используй ⚠️ Не документируй `` 1587 | 1588 | Фактически означает **Unauthenticated**. Учетные данные отсутствуют или недействительны для целевого ресурса. Для API это обычно означает, что предоставленный токен или cookie не действительны. Поскольку такое может произойти почти с каждым endpoint-ом, API обычно не должны документировать это. 1589 | 1590 | 1591 | ##### 403 Forbidden 1592 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-403-forbidden) ⚠️ Не документируй `` 1593 | 1594 | Означает, что **сервер принимает запрос, но отказывает в доступе из-за недостаточных прав или политик сервиса**. Для API это может означать, что токен запроса был действительным, но в нем отсутствовал scope для данного endpoint-а. Или что не удалось выполнить какую-то специфическую для объекта авторизацию. Мы рекомендуем для этого кода документировать только второй случай. 1595 | 1596 | Также этот код ответа может трактоваться не верно, в связке с другими **4**** кодами. А еще есть риск утечки информации, который может дать понять злоумышленнику что ресурс существует. 1597 | Ниже таблица когда какой код рекомендуется использовать: 1598 | | Ситуация | Код ответа | Причина | 1599 | |---------------------------------------|-------------------|---------------------------------------------| 1600 | | Клиент не передал `Authorization` | `401 Unauthorized`| Запрос требует аутентификации | 1601 | | Клиент передал неверный токен | `401 Unauthorized`| Аутентификация провалена | 1602 | | Клиент залогинен, но не имеет доступа | `403 Forbidden` | У пользователя недостаточно прав | 1603 | | Клиент запрашивает чужие данные | `404 Not Found` | Политика API запрещает доступ | 1604 | | Ресурса не существует или скрыт | `404 Not Found` | Защита от утечек информации | 1605 | 1606 | 1607 | ##### 404 Not found 1608 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-404-not-found) ✅ Используй ⚠️ Не документируй `` 1609 | 1610 | Целевой ресурс не найден. Этот код ответа будет возвращен большинством путей в большинстве API (без документации), а также для endpoint-ов с параметрами в запросе, когда эти параметры не могут быть сопоставлены с существующей сущностью на сервере. Для `PUT` endpoint-ов, которые поддерживают только обновление существующих ресурсов, этот код может быть возвращен, если ресурс не существует. За исключением этих особых случаев, этот статус не нужно документировать. 1611 | 1612 | ##### 405 Method Not Allowed 1613 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-405-method-not-allowed) ✅ Документируй `` 1614 | 1615 | Метод запроса не поддерживается для данного ресурса. Теоретически, этот код может быть возвращен для всех ресурсов для всех методов, кроме тех, которые задокументированы. Использование этого кода ответа для существующего endpoint-а (обычно с параметрами пути) имеет смысл только в том случае, если от внутреннего состояния ресурса зависит, разрешен ли определенный метод, например, заказ можно отменить только через `DELETE`, пока груз не покинет склад. 1616 | 1617 | **Не используйте этот статус код, если у вас нет специального случая, но тогда обязательно документируйте его, чтобы было понятно, почему ресурс может не поддерживать тот или иной метод.** 1618 | 1619 | ##### 406 Not Acceptable 1620 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-406-not-acceptable) ✅ Используй ⚠️ Не документируй `` 1621 | 1622 | Сервер не может вернуть данные в формате, который клиент указал в заголовке `Accept`. 1623 | 1624 | ##### 408 Request timeout 1625 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-408-request-timeout) ❌ Не используй `` 1626 | 1627 | Сервер не получил полный запрос от клиента за отведенное время. Для API этот код использовать не стоит. 1628 | 1629 | ##### 409 Conflict 1630 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-409-conflict) ✅ Документируй `POST`, `PUT`, `PATCH`, `DELETE` 1631 | 1632 | Запрос не может быть выполнен из-за конфликта с текущим состоянием ресурса. Например, при попытке создать ресурс, который уже существует. Или конфликты возникающие при редактировании ресурса, который изменился с момента последнего получения, тогда можно вернуть **409** как индикатор того, что клиенту нужно повторно запросить данные перед обновлением. 1633 | 1634 | Если такой способ используется, он должен быть задокументирован. Для успешного надежного создания ресурсов (PUT или POST) вы всегда должны возвращать **200** или **201**, а не **409**, даже если ресурс уже существует. Если какие-либо заголовки `If-*` вызывают конфликт, вы должны использовать **412**, а не **409**. Применимо только к методам, которые что-то изменяют. 1635 | 1636 | ##### 410 Gone 1637 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-410-gone) ⚠️ Не документируй `` 1638 | 1639 | Ресурса больше не существует. Он существовал в прошлом и, скорее всего, не будет существовать в будущем. Это может использоваться, например, при доступе к ресурсу, который был намеренно удален. Обычно это не нужно документировать, если только нет особой необходимости отличать этот случай от обычного **404**. 1640 | 1641 | ##### 411 Length Required 1642 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-411-length-required) ✅ Документируй `POST`, `PUT`, `PATCH` 1643 | 1644 | Серверу требуется заголовок `Content-Length` для этого запроса. Обычно это актуально только для загрузки больших файлов. Соответствующий заголовок должен быть отмечен как обязательный. Если он используется, он должен быть документирован. 1645 | 1646 | ##### 412 Precondition Failed 1647 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-412-precondition-failed) ✅ Используй ⚠️ Не документируй `PUT`, `PATCH`, `DELETE` 1648 | 1649 | Возвращается для условных запросов, например, `If-Match`, если условие не выполнилось. Используется для оптимистичной блокировки. Обычно применяется только к методам, которые что-то изменяют. Для запросов `HEAD`, `GET` вместо этого используйте **304**. 1650 | 1651 | ##### 415 Unsupported Media Type 1652 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-415-unsupported-media-type) ✅ Используй ⚠️ Не документируй `POST`, `PUT`, `PATCH` 1653 | 1654 | Клиент не предоставил поддерживаемый `Content-Type` для тела запроса. Применимо только к методам с телом запроса. 1655 | 1656 | ##### 417 Expectation Failed 1657 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-417-expectation-failed) ❌ Не используй `` 1658 | 1659 | Возвращается, если клиент использовал заголовок `Expect`, который сервер не поддерживает. Единственное определенная ценность для заголовка `Expect` является очень технической и не относится к API. 1660 | 1661 | ##### 418 I’m a teapot 🫖 1662 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-418-unused) ❌ Не используй `` 1663 | 1664 | Используйте только в том случае, если вы реализуете API для чайника, который не поддерживает заваривание кофе. Этот код является первоапрельской шуткой из [RFC 2324](https://www.rfc-editor.org/rfc/rfc2324.html). Его не стоит использовать в API. 1665 | 1666 | ##### 422 Unprocessable Content 1667 | [RFC](https://tools.ietf.org/html/rfc9110#name-422-unprocessable-content) ❌ Не используй `` 1668 | 1669 | Сервер понимает тип содержимого, но не может его обработать. Мы не рекомендуем использовать этот код, так как **400** уже покрывает большинство случаев использования, и, кажется, нет явной пользы от различия между ними. 1670 | 1671 | ##### 423 Locked 1672 | [RFC](https://datatracker.ietf.org/doc/html/rfc4918#section-11.3) ✅ Документируй `PUT`, `PATCH`, `DELETE` 1673 | 1674 | 1675 | Пессимистичная блокировка, например, состояния обработки. Может использоваться для указания существующей блокировки ресурса, однако мы рекомендуем использовать оптимистичную блокировку. Если используется, то должно быть документировано, чтобы указать на пессимистичную блокировку. 1676 | 1677 | ##### 424 Failed Dependency 1678 | [RFC](https://datatracker.ietf.org/doc/html/rfc4918#section-11.4) ❌ Не используй `` 1679 | 1680 | Запрос завершился неудачей из-за отказа предыдущего запроса. Это не относится к RESTful API. 1681 | 1682 | ##### 428 Precondition Required 1683 | [RFC](https://datatracker.ietf.org/doc/html/rfc6585#section-7.1) ✅ Используй ⚠️ Не документируй `` 1684 | 1685 | Используется для обозначения ситуации, когда сервер требует выполнения предварительного условия перед выполнением запроса, например для избежания проблемы "lost update", когда клиент может попытаться изменить ресурс, при этом не получив последнюю его версию. Вместо документирования этого кода ответа, добавляйте в документацию используемые заголовки для таких сценариев. 1686 | 1687 | Для большинства сценариев с обычным API предпочтительнее использовать стандартные коды ошибок, такие как **409** или другие более простые подходы для управления состоянием. 1688 | 1689 | 1690 | ##### 429 Too many requests 1691 | [RFC](https://datatracker.ietf.org/doc/html/rfc6585#section-7.2) ✅ Используй ⚠️ Не документируй `` 1692 | 1693 | Используется для указания на то, что клиент отправил слишком много запросов за ограниченный период времени и должен замедлить свои запросы. 1694 | 1695 | 1696 | ##### 431 Request Header Fields Too Large 1697 | [RFC](https://datatracker.ietf.org/doc/html/rfc6585#section-7.3) ⚠️ Не документируй `` 1698 | 1699 | Сервер не может обработать запрос из-за слишком большого размера заголовков запроса. Обычно используется шлюзами и прокси-серверами с ограничениями по объему памяти. 1700 | 1701 | 1702 | #### Ошибки сервера 1703 | 1704 | 1705 | ##### 500 Internal Server Error 1706 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-500-internal-server-error) ✅ Используй ⚠️ Не документируй `` 1707 | 1708 | Общий признак ошибки, связанной с непредвиденной проблемой выполнения сервера. Клиенты должны быть осторожны с повторными попытками при получении этого ответа, поскольку природа проблемы неизвестна и возможно повторится. 1709 | 1710 | ##### 501 Not Implemented 1711 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-501-not-implemented) ✅ Документируй `` 1712 | 1713 | Сервер не может выполнить запрос, поскольку endpoint еще не реализован. Обычно это подразумевает доступность в будущем, но повторять попытку запроса сейчас не рекомендуется. Может быть задокументировано для endpoint-ов, которые планируется реализовать в будущем, чтобы указать, что они пока недоступны. 1714 | 1715 | ##### 502 Bad Gateway 1716 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-502-bad-gateway) ✅ Используй ⚠️ Не документируй `` 1717 | 1718 | Этот статус может быть возвращен автоматически вашим API Gateway или балансировщиком нагрузки (например, Nginx) при проблемах с бэкендом. Может использоваться сервером для указания на то, что входящий сервис выдает неожиданный результат вместо **500**. Клиенты должны быть осторожны с повторными попытками при получении этого ответа, поскольку природа проблемы неизвестна и возможно повторится. 1719 | 1720 | Но не стоит вручную выставлять **502** в коде вашего приложения. Внутренние ошибки лучше обрабатывать и отдавать **503 Service Unavailable** с указанием **Retry-After**. 1721 | 1722 | 1723 | ##### 503 Service Unavailable 1724 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-503-service-unavailable) ✅ Используй ⚠️ Не документируй `` 1725 | 1726 | Сервис (временно) недоступен. Клиенту рекомендуется повторять запросы по экспоненциальной схеме. Если возможно, сервис должен указать, как долго клиент должен ждать, установив заголовок **Retry-After**. 1727 | 1728 | ##### 504 Gateway Timeout 1729 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#name-504-gateway-timeout) ✅ Используй ⚠️ Не документируй `` 1730 | 1731 | Означает, что сервер-шлюз(например, API-Gateway, прокси или балансировщик нагрузки) **не дождался ответа от бэкенд-сервера в установленный таймаут. 1732 | 1733 | Но не стоит вручную выставлять **504** в коде вашего приложения. Внутренние ошибки лучше обрабатывать и отдавать **503 Service Unavailable** с указанием **Retry-After**. 1734 | 1735 | ##### 505 HTTP Version Not Supported 1736 | [RFC](https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.6) ❌ Не используй `` 1737 | 1738 | Сервер не поддерживает версию протокола HTTP, использованную в запросе. Технический код ответа, который не используется в RESTful API. 1739 | 1740 | ##### 507 Insufficient Storage 1741 | [RFC](https://datatracker.ietf.org/doc/html/rfc4918#section-11.5) ⚠️ Не документируй `POST`, `PUT`, `PATCH` 1742 | 1743 | Сервер не может сохранить ресурс, необходимый для выполнения запроса. Может использоваться для указания на то, что на сервере закончилось дисковое пространство. 1744 | 1745 | ##### 511 Network Authentication Required 1746 | [RFC](https://datatracker.ietf.org/doc/html/rfc6585#section-7.4) ❌ Не используй `` 1747 | 1748 | Клиенту необходимо пройти аутентификацию, чтобы получить доступ к сети. Технический код ответа, который не используется в RESTful API. 1749 | 1750 | 1751 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Инструменты для API First 2 | 3 | > 🛠 Подборка проверенных инструментов для работы по API First в банке 4 | 5 | - [Инструменты для API First](#инструменты-для-api-first) 6 | - [Редакторы спецификаций](#редакторы-спецификаций) 7 | - [VS Code + расширения](#vs-code--расширения) 8 | - [IntelliJ IDEA + плагины](#intellij-idea--плагины) 9 | - [Stoplight Studio](#stoplight-studio) 10 | - [Кодогенерация](#кодогенерация) 11 | - [OpenAPI Generator](#openapi-generator) 12 | - [Пример настройки кодогенерации в Gradle](#пример-настройки-кодогенерации-в-gradle) 13 | - [Modelina - генерация моделей на основе AsyncAPI](#modelina---генерация-моделей-на-основе-asyncapi) 14 | - [Mock-серверы](#mock-серверы) 15 | - [Prism by Stoplight](#prism-by-stoplight) 16 | - [Wiremock - генерация моделей на основе AsyncAPI](#wiremock---генерация-моделей-на-основе-asyncapi) 17 | - [Тестирование](#тестирование) 18 | - [Pact](#pact) 19 | - [Spring Cloud Contract](#spring-cloud-contract) 20 | - [Валидация](#валидация) 21 | - [Spectral by Stoplight](#spectral-by-stoplight) 22 | - [Vacuum Quobix](#vacuum-quobix) 23 | - [Документация](#документация) 24 | - [Redocly](#redocly) 25 | - [Docusaurus + OpenAPI Plugin](#docusaurus--openapi-plugin) 26 | - [Swagger UI](#swagger-ui) 27 | - [OpenAPI Generator](#openapi-generator-1) 28 | 29 | 30 | ## Редакторы спецификаций 31 | 32 | ### VS Code + расширения 33 | **Рекомендуется для большинства команд** 34 | - ✅ Бесплатный 35 | - ✅ Автодополнение для OpenAPI 36 | - ✅ Визуализация OpenAPI в Swagger UI прямо в редакторе 37 | - ✅ Встроенная валидация по схеме 38 | - ✅ Поддержка Spectral плагина 39 | - ❌ Ручное редактирование спецификации 40 | 41 | **Ссылки** 42 | - [VS Code](https://code.visualstudio.com/) 43 | - [Плагин - OpenAPI (Swagger) Editor](https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi) 44 | - [Плагин - Spectral](https://marketplace.visualstudio.com/items?itemName=stoplight.spectral) 45 | 46 | ### IntelliJ IDEA + плагины 47 | **Для Java разработчиков** 48 | - ✅ Интеграция с кодом 49 | - ✅ Рефакторинг 50 | - ✅ Генерация кода 51 | - ✅ Привычно для JVM разработчиков 52 | - ❌ Ручное редактирование спецификации 53 | - ❌ В Community версии встроенный плагин не работает, нужно искать аналоги 54 | 55 | 56 | ### Stoplight Studio 57 | **Для визуального проектирования** 58 | - ✅ Визуальный редактор 59 | - ✅ Встроенная документация 60 | - ✅ Встроенная проверка по правилам Spectral 61 | - ❌ Нет контроля над выходной спецификацией 62 | - ❌ Выходная спецификация может требовать ручной корректировки 63 | - ❌ Платный для команд 64 | 65 | ## Кодогенерация 66 | 67 | ### OpenAPI Generator 68 | **Универсальное решение** 69 | 70 | - Из OpenAPI можно получить код для сервера, клиента, документации, тестов, postman-коллекции и т.д. 71 | - Интегрируется как через CLI, так и через Gradle/Maven плагин 72 | - Имеет самое обширное коммьюнити среди доступных решений на рынке 73 | 74 | Поддерживает самые популярные в банке языки: 75 | - **Backend**: Java/Kotlin (Spring), Go, Python (FastAPI) 76 | - **Frontend**: TypeScript (Axios, Fetch), JavaScript 77 | - **Mobile**: Kotlin, Swift 78 | 79 | **Ссылки** 80 | - [OpenAPI Generator](https://openapi-generator.tech/) 81 | - [Доступные генераторы](https://openapi-generator.tech/docs/generators) 82 | - [Gradle плагин](https://plugins.gradle.org/plugin/org.openapi.generator) 83 | - [Maven плагин](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin) 84 | 85 | #### Пример настройки кодогенерации в Gradle 86 | 87 | ```kotlin 88 | plugins { 89 | kotlin("jvm") version "2.0.20" 90 | id("org.openapi.generator") version "7.11.0" 91 | } 92 | 93 | group = "ru.raif" 94 | version = "1.0-SNAPSHOT" 95 | 96 | repositories { 97 | mavenCentral() 98 | } 99 | 100 | dependencies { 101 | testImplementation(kotlin("test")) 102 | } 103 | 104 | openApiGenerate { 105 | globalProperties.set( 106 | mapOf( 107 | "models" to "" 108 | ) 109 | ) 110 | generatorName.set("spring") 111 | inputSpec.set("$rootDir/specs/openapi.yaml") 112 | outputDir.set("${buildDir}/generated") 113 | modelPackage.set("ru.raif.model") 114 | } 115 | 116 | tasks.test { 117 | useJUnitPlatform() 118 | } 119 | kotlin { 120 | jvmToolchain(21) 121 | } 122 | ``` 123 | 124 | ### Modelina - генерация моделей на основе AsyncAPI 125 | **Лучший генератор моделей для асинхронных систем** 126 | 127 | - ✅ Позволяет адаптировать API First для асинхронных систем/сервисов 128 | - ✅ Легко встраивается в пайплайн с помощью CLI 129 | - ✅ AsyncAPI описывает специфику очередей и топиков лучше чем OpenAPI 130 | - ❌ Конфигурация пишется на Typescript, нужно базовое понимание 131 | - ❌ Для кастомизации моделей, нужно писать на Typescript 132 | - ❌ AsyncAPI не такой зрелый как OpenAPI, могут быть баги 133 | 134 | 135 | **Ссылки** 136 | - [Modelina](https://modelina.org/examples) 137 | - [Пример настройки генерации Kotlin моделей](https://modelina.org/examples?selectedExample=generate-kotlin-models) 138 | - [Пример использования генерации моделей в команде CDC Integrations](https://gitlabci.raiffeisen.ru/cdc-integrations/analytics/api-spec/-/blob/main/plugin/scripts/generateModels.ts) 139 | 140 | 141 | ## Mock-серверы 142 | 143 | ### Prism by Stoplight 144 | **Рекомендуется для быстрого старта** 145 | - ✅ Простая установка 146 | - ✅ Динамические примеры 147 | - ✅ Валидация запросов 148 | - ✅ Бесплатный 149 | 150 | **Ссылки** 151 | - [Prism](https://github.com/stoplightio/prism) 152 | 153 | ### Wiremock - генерация моделей на основе AsyncAPI 154 | **Отличный выбор для JVM разработчиков** 155 | - ✅ Java-friendly 156 | - ✅ Есть standalone версия 157 | - ✅ Запись/воспроизведение 158 | - ✅ Программируемые сценарии 159 | - ✅ Отлично вписывается в процесс тестирования 160 | 161 | **Ссылки** 162 | - [Wiremock](https://wiremock.org/) 163 | - [Kotlin генератор для wiremock](https://openapi-generator.tech/docs/generators/kotlin-wiremock/) 164 | - [Java генератор для wiremock](https://openapi-generator.tech/docs/generators/java-wiremock/) 165 | 166 | 167 | ## Тестирование 168 | 169 | ### Pact 170 | **Контрактное тестирование для микросервисов** 171 | - ✅ Consumer-driven contracts 172 | - ✅ Версионирование контрактов 173 | - ✅ Broker для хранения 174 | 175 | **Ссылки** 176 | - [Pact.io](https://docs.pact.io/) 177 | 178 | ### Spring Cloud Contract 179 | **Отличный выбор для JVM разработчиков** 180 | 181 | **Ссылки** 182 | - [Spring Cloud Contract](https://spring.io/projects/spring-cloud-contract) 183 | 184 | ## Валидация 185 | 186 | ### Spectral by Stoplight 187 | **Отличный выбор для JVM разработчиков** 188 | 189 | 190 | - ✅ Кастомные правила 191 | - ✅ Интеграция с CI/CD 192 | - ✅ Расширяемость 193 | - ✅ Поддержка всех форматов 194 | - ❌ Написан на JS, может быть медленным в CI/CD 195 | 196 | **Ссылки** 197 | - [Spectral](https://github.com/stoplightio/spectral) 198 | 199 | ### Vacuum Quobix 200 | - ✅ Основан на стандарте правил Spectral 201 | - ✅ Очень быстрый - написан на Go 202 | - ✅ Имеет различные форматы отчетов(HTML, JUnit, JSON) 203 | - ✅ Имеет встроенный набор правил 204 | 205 | **Ссылки** 206 | - [Vacuum](https://quobix.com/vacuum/about/) 207 | - [Пример интеграции в Gradle в команде CDC Integrations](https://gitlabci.raiffeisen.ru/cdc-integrations/analytics/api-spec/-/blob/main/plugin/build.gradle.kts?ref_type=heads#L659) 208 | 209 | ## Документация 210 | 211 | ### Redocly 212 | **Простая в настройке документация** 213 | 214 | - ✅ Красивый дизайн 215 | - ✅ Кастомизация 216 | - ✅ SEO-friendly 217 | - ✅ Встроенные примеры кода 218 | 219 | **Ссылки** 220 | - [Redocly](https://redocly.com/) 221 | - [Пример документации](https://pay.raif.ru/doc/sbp.html) 222 | 223 | ### Docusaurus + OpenAPI Plugin 224 | **Для комплексной документации** 225 | - ✅ Markdown поддержка 226 | - ✅ Версионирование 227 | - ✅ Поиск 228 | - ✅ Кастомные страницы 229 | 230 | **Ссылки** 231 | - [Docusaurus](https://docusaurus.io/) 232 | - [Docusaurus OpenAPI Plugin](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs) 233 | - [Пример документации](https://developer.raiffeisen.ru/docs/api) 234 | 235 | ### Swagger UI 236 | **Стандартное решение** 237 | - ✅ Интерактивная документация 238 | - ✅ Доступен в VS Code/IDE по-умолчанию. Также встроен в Gitlab 239 | - ✅ Try it out 240 | - ✅ Простая интеграция 241 | 242 | **Ссылки** 243 | - [Swagger UI](https://swagger.io/tools/swagger-ui/) 244 | - [Swagger UI в Gitlab](https://docs.gitlab.com/api/openapi/openapi_interactive/) 245 | 246 | 247 | ### OpenAPI Generator 248 | **Тоже умеет генерировать документацию** 249 | 250 | - Набор генераторов документации в различных форматах таких как md, asciidoc, html и тп 251 | 252 | **Ссылки** 253 | - [OpenAPI Generator](https://openapi-generator.tech/) 254 | - [Доступные генераторы](https://openapi-generator.tech/docs/generators) -------------------------------------------------------------------------------- /use-cases/README.md: -------------------------------------------------------------------------------- 1 | # Use Cases - руководства для специфических типов API: 2 | 3 | 4 | - Файловое API (upload/download) 5 | - Асинхронное API (async tasks, webhooks) 6 | - Batch операции 7 | - GraphQL в банке 8 | - Event-driven API 9 | 10 | > ...будет наполняться --------------------------------------------------------------------------------