├── .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 |
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 | 
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 | > ...будет наполняться
--------------------------------------------------------------------------------