В этом репозитории находится пример спецификации (папка example) и описаны правила работы с ней, а также распространенные кейсы (файл cases).
- Лучшии практики ведения API спецификации (OpenAPI) в Surf
- Содержание
- Общие принципы
- Организация файлов и папок
- Проектирование спецификации API
- Инструменты
- Генерация папок для фичи
- Базовая структура
- Ресурсы и методы
- Структура и проектирование моделей
- Быстрые и полезные комбинации
- Проверка спецификации API на фичу
- Проверка всей спецификации API через линтер SurfGen
- Дополнительная информация для ознакомления и советы
- Спецификация должна быть побита на разные файлы. Это необходимо для того, чтобы ее можно было легко и приятно поддерживать (дополнять, изменять) и вообще читать.
- Корневой README.md должен содержать информацию о том, как работать с источниками в репозитории. Потому что кто-то может быть не в курсе.
- Хорошо иметь скрипт для автогенерации шаблона. Чтоб не копипастить каждый раз самим.
- Старайтесь использовать текстовый формат (не используйте GUI), потому что так проще навигировать. И так можно пользоваться поиском.
- Относитесь к спецификации как к программному коду. Иначе в конечном итоге она превратится в мусор.
Хорошо придерживаться следующего паттерна:
- root_folder <- корень вашего репозитория
-- README.md
-- feature_or_api_controller <- папка, имеющая название фичи
--- api.yaml <- Файл исключительно для описание сервисов (path в Swagger)
--- models.yaml <- Файл исключительно для описания моделей (components/schemas в Swagger)
--- parameters.yaml <- Файл исключительно для описания параметров api-методов (components/parameters в Swagger)
--- errors.yaml <- Файл исключительно для описания ошибок которые могут вернуть методы (components/schemas в Swagger)
ВАЖНО
api.yamlиmodels.yamlобязательны! Потому что в противном случае люди будут бояться лезть менять ваши файлы.parameters.yamlиerrors.yamlне обязательны! Они могут быть использованы в тех случаях, когда сервисы содержат очень много повторяющихся параметров и/или ошибок.- Не стоит выносить отдельно components/requestBodies , потому что тогда, чтобы добраться от метода до модели, потребуется 2 перехода. Это уже неудобно.
Перед проектированием спецификации API подразумевается, что вы:
- Клонировали репозиторий и наполнили его файлами для генерации и readme.
- Создали ветку фичи, которую будете проектировать.
- Установили необходимые расширения в VSCode.
- VSCode скачать и установить, если еще не установлен.
- Расширения для VSCode - для установки переходим в раздел Расширения в левом боковом меню и ищем по названию необходимое расширение:
- Swagger Viewer - Предварительный просмотр спецификации API, происходит в режиме реального времени по мере ввода.
- GitHub Pull Requests and Issues (опционально) - можно смотреть и комментировать PR-ы прямо из VSCode. Необходимо авторизоваться через VSCode в GitHub, появится иконка GitHub-а в боковом меню, где можно просматривать и комментировать PR-ы.
- Git Blame (опционально). Расширение Git Blame предоставляет возможность просматривать информацию состояния для текущей выбранной строки. Оно позволяет выяснить, кто писал определенные фрагменты кода.
- Git History (опционально). Расширение Git History предоставляет возможность тщательно изучить историю файла, автора, ветки. Чтобы активировать окно Git History, нужно кликнуть на файл правой кнопкой мыши и выбрать Git: View File History. Кроме того, вы можете сравнивать ветки и коммиты, создавать ветки из коммитов и многое другое.
Хорошо иметь какой-то инструмент, который позволит сгенерить нужные файлы с предзаполненной мета информацией - чтоб люди не писали по 100 раз одно и то же.
В этом репозитории это сделано с помощью шелл-скрипта gen.sh и двух файлов с шаблонами .api_template и .models_template
Сам скрипт позволяет сгенерировать "контроллер" с отдельным файлом для моделек и отдельным файлом для методов API. Т.к. мы проектируем уже фичу, то все махинации должны производиться в соответствующей ветке.
Пошаговая инструкция генерации папки для фичи:
| № | Шаг |
|---|---|
| 1 | Проверяем, что мы в правильной ветке. Если работаем над авторизацией, то в ветке auth, которую мы создали. |
| 2 | Открываем консоль, перемещаемся в корень репозитория: 1. Идем в папку где располагается репозиторий (к примеру, E:\work\my-project-swagger). 2. Shift+клик по правой кнопка мыши → “Открыть окно PowerShell здесь”, на macOS соответственно терминал открываем или же через терминал VSCode. |
| 3 | Вводим в консоль ./gen.sh ./{название фичи (оно же название папки)}. Пример: ./gen.sh ./auth или sh gen.sh catalog |
| 4 | Скрипт создаст папку catalog и добавит в нее два файла api.yaml и models.yaml с уже заполненной шапкой. Если папка уже есть, то скрипт просто положит в нее два файла. Всё, папки появились. Если нет, жмем кнопку обновления проводника (Explorer) в VSCode. Созданы два файла в папке auth с нужными шапками/шаблонами: api.yaml - для описания эндпоинтов, models.yaml - для описания моделей к ним |
| 5 | Можем начинать проектирование фичи, для которой создали папку. |
Структура файла api.yaml или что нагенерил мне скрипт:
Все поля, кроме
path, заполняются при генерации папок. Но понимать, что они означают будет полезно.
| Название поля | Описание |
|---|---|
openapi |
Обязательное для заполнения. Номер версии спецификации OpenAPI. Последняя версия на данный момент 3.0.2. Это поле не связано со строкой API - info.version. |
info |
Обязательное для заполнения. Содержит основную информацию о вашем API: название ( title), описание вашего API (description), версия вашего API (version), контакты разработчика спецификации (contact.name, contact.email). В данной инструкции указан не весь набор элементов, которые могут содержаться в info-блоке, но для нашего использования этого достаточно. Пример: info:
title: "API"
version: "1.0.0"
contact:
name: Юльская Виктория
email: [email protected] |
servers |
Содержит информацию об используемых серверах: url и описание сервера (description). Их может быть несколько. Пример: servers:
- url: https://dev3.myproject.ru/api/surf/v1/
description: Test server dev3
- url: https://surf.myproject.ru/api/surf/v1/
description: Test server surf
- url: https://myproject.ru/api/surf/v1/
description: Production Server |
components |
В объекте components можно хранить множество различных переиспользуемых объектов. Объект components может содержать следующее: При делении папки на два файла api.yaml и models.yaml нам данный блок нужен только для определения схемы безопасности, все остальное уходит в файл models.yaml. Лучше сразу понять как будет проходить авторизация и дальнейшая проверка наличия прав пользователя при запросе на ресурс - через токены / куки / что-то другое (разработчикам надо закладывать это в самом начале, во время первого спринта, а то и во время инициализации). Пример: components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT |
security |
Для отправки запросов, авторизованных нашим сервером API, спецификация должна содержать информацию о безопасности, которая авторизует запрос. security:
- bearerAuth: []Объявленные поля components.securitySchemes и security свидетельствуют о том, что у любого метода в этом файле должен быть установлен хедер Authorization с JWT токеном. |
paths |
Обязательное для заполнения. Содержит доступные пути (конечные точки) и операции (методы) для API. Подробнее о заполнении данного блока рассмотрим чуть ниже. |
Блок path состоит из:
- пути (конечной точки) - все пути в блоке
pathзадаются относительно URL, определенных в блоке "Серверы”, то есть полный URL запроса будет выглядеть так<server-url>/path. - операций (методов
GET,POSTи тд), который в свою очередь включает:summary- название метода.description- описание работы метода. Описывайте там задачу которую решает метод или свойство.security: []- указывается если для запроса НЕ нужна авторизация.parameters- параметры запросаrequestBody- тело запросаresponses- описание ответа
Есть и другие элементы, которыми нам особо не нужно пользоваться пока что.

Есть 3 типа ресурсов:
- Документ - один объект. К примеру, одно сообщение в списке (
api/messages/{id}- документ обычно вложен в коллекцию, но есть исключения).- в пути используются в таком случае только существительные.
- последнее существительное в единственном числе.
- Коллекция - множество объектов. К примеру, список сообщений (
api/messages).- в пути используются в таком случае только существительные.
- последнее существительное во множественном числе.
- Контроллер - действие. К примеру, оформление заказа (
api/cart/checkout).- можно использовать глаголы.
- последнее слово всегда глагол.
- действие всегда должно относится к чему то (
api/cart/checkout- checkout относится к корзине, не может быть простоapi/checkout).
Стараемся делать как можно больше документов и коллекций, и как можно меньше контроллеров
В названии пути НЕ ПИШЕМ ДЕЙСТВИЕ, о котором говорит HTTP method!!! (create, update, delete и тд)
- POST /courses - Создать новый курс
- POST /courses/create - Создать новый курс
Параметры пути и запрос состоят из:
name: имя параметра.in: место параметра. Возможные значения:header- параметры, включенные в заголовок запроса, обычно относятся к авторизации.path- параметры в пределах path конечной точки перед строкой запроса. Обычно эти параметры выделяются фигурными скобками.query- параметры в строке запроса конечной точки, располагаются после знака ?.cookie- параметры в заголовке Cookie.
description: описание параметра.required: требуется ли параметр.schema: схема или модель для параметра. Схема определяет структуру входных или выходных данных.example: пример типа носителя. Если объект example содержит примеры, эти примеры появляются в Swagger UI, а не в содержимом объекта example.
Также, параметры запроса можно выносить в models.yaml и ссылаться ($ref) на параметры из моделей. Пример:
parameters:
- $ref: "models.yaml#/components/parameters/Param1"Для добавления в компоненты параметров необходимо на уровне с элементом schema добавить элемент parameters и описать там все необходимые параметры.
Для ограничения возможных значений параметра запроса необходимо использовать ключевое слово enum.
# Описание параметра запроса в models.yaml для того, чтобы ссылаться на него и переиспользовать без дублирующего описания.
parameters:
filter_type:
name: filter_type
in: query
description: |
Тип фильтра заказов пользователя:
- all - все заказы
- current - текущие
- done - выполненные
schema:
enum: ["all", "current", "done"]
type: stringДля того чтобы добавить параметр в путь запроса необходимо использовать фигурный скобки {}. Обычно это используется для указания определенного элемента в коллекции. Путь может иметь несколько параметров:
GET /users/{id}:
GET /cars/{carId}/drivers/{driverId}:Каждый параметр пути должен быть заменен фактическим значением при вызове.
Для определения параметров пути нужно использовать следующую конструкцию in: path. Необходимо также добавить required: true, чтобы указать обязательность данного параметра.
paths:
/users/{id}:
get:
parameters:
- name: id # имя можно использовать такое же как и в пути
in: path
description: Идентификатор пользователя
required: true # обязательный параметр
schema:
type: integer
minimum: 1Параметры запроса отображаются в конце URL-адреса после знака вопроса (?). Несколько значений должны разделяться амперсандом (&).
GET /pets/findByStatus?status=available
GET /notes?offset=100&limit=50
Для определения таких параметров нужно использовать следующую конструкцию in: query.
paths:
/notes:
get:
parameters:
- name: offset
in: query
description: The number of items to skip before starting to collect the result set
schema:
type: integer
- name: limit
in: query
description: The numbers of items to return
schema:
type: integerНе декларируйте здесь объекты!!!
Примеры оформления параметров запроса
Про параметры заголовка и куки подробнее можно прочитать в соответствующих разделах.
POST, PUT и PATCH запросы могут иметь тело запроса.
1. Мы всегда должны ставить ссылки на модели!!! Не нужно засорять нашу спецификацию перечислением того, что должно быть в моделях. У нас и так огромные методы, а если еще модели писать, то будет много дублирования и иных проблем. Делаем ссылки для своего удобства и для удобства всей команды.
2. Есть исключения в виде массивов или групп, в таком случае мы прописываем массив и как тип элементов, которые там лежат мы используем ссылку на модель элемента.
Пример:
requestBody:
required: true
content:
application/json:
schema:
$ref: "models.yaml#/components/schemas/RecalculateOrderRequest"Описание REST-запроса обязательно должно содержать описание ответа (responses). У каждого метода должен быть определен хотя бы один ответ (успешный). Response задается HTTP-кодом ответа и данными, которые возвращаются в теле ответа и / или заголовке.
1. Мы всегда должны ставить ссылки на модели!!! Не нужно засорять нашу спецификацию перечислением того, что должно быть в моделях. У нас и так огромные методы, а если еще модели писать, то будет много дублирования и иных проблем. Делаем ссылки для своего удобства и для удобства всей команды.
2. Есть исключения в виде массивов или групп, в таком случае мы прописываем массив и как тип элементов, которые там лежат мы используем ссылку на модель элемента.
Описание ответа начинается с кода, такого как 200 или 404. Методы обычно возвращают один успешный код и один и более кодов ошибок. Каждый код требуется описания (description) - условие, при которых код срабатывает. Если вы не можете задать определенный код, то его можно задать следующим видом: 1XX, 2XX, 3XX, 4XX, 5XX. Но таким образом, в случае если был задан код 404 и 4XX, приоритет у первого будет выше.
responses:
'201':
description: Бонусы успешно списаны.
'500':
description: |
Возможные ошибки
* `101` - UserBlocked, пользователь был заблокирован
* `104` - OTPCodeInvalid, неверный OTP-код
content:
application/json:
schema:
$ref: "../common/models.yaml#/components/schemas/ErrorResponse"
'426':
description: Необходимо обновить приложениеНе стоит описывать все возможные коды ответов, тем более что о некоторых из них можно и не знать в момент проектирования запроса. Важно при описании кодов покрыть случай успешного выполнения запроса и коды ошибок, известных на момент написания REST-запроса.
Также, в Surf обычно описываются кастомные ошибки и заворачиваются в400или500статус код.
Кастомные ошибки описываются в отдельной папке common - где вapi.yamlописывается справочник ошибок, а вmodels.yamlописывается модель ошибки, к примеру,ErrorResponse, который состоит из кода кастомной ошибки, сообщения в человекочитаемом виде, и при необходимости вспомогательная информация об ошибке
Для передачи файлов в запросе или ответе в OpenAPI 3.0 используется type: string и format: binary или format: base64.
paths:
/report:
get:
summary: Returns the report in the PDF format
responses:
'200':
description: A PDF file
content:
application/pdf:
schema:
type: string
format: binaryСтатус коды
| Код | Описание | Часто используемые коды |
|---|---|---|
| 2xx | Операция завершилась успешно | 200 - Все ок! Всегда содержит тело ответа. Может использоваться в GET запросах. 201 - Запись создана. Используется в методах POST и имеет тело ответа, чтобы сказать клиенту, что мы создали в итоге - как минимум получить идентификатор записи). 202 - Принято. Не содержит тело ответа. Говорит о том, что клиенту не обязательно ждать завершения операции (но она еще не завершилась). Пример, оплата. 204 - Операция прошла успешно, но ответ пустой. Если знаем что мы не ждем ответа, то ставим всегда данный код. |
| 3xx | Редирект или можем пойти читать из кэша | 304 - Данные не изменились. Можно читать данные из кеша. Обычно работает с E-Tag или Cache-Control заголовками. Работает только с GET запросами |
| 4xx | Операция завершилась с ошибкой по вине клиента | Из тех, что стоит фиксировать в спецификации: 401 - Пользователь не авторизован для доступа. 403 - Пользователь не имеет права просматривать контент. 426 - Указывает, что сервер отказывается выполнять запрос с использованием текущего протокола, но может захотеть сделать это после того, как клиент обновится до другого протокола (используется когда версия приложения уже не поддерживается и пользователю предлагается обновить приложение при получении данной ошибки). Также, на 400 или 409 можно повесить кастомные ошибки и описать их в справочнике |
| 5xx | Операция завершилась с ошибкой по вине сервера (или не смог сразу определить что по вине клиента) | Конкретные 5xx ошибки не фиксируем обычно в спецификации API, но если необходима необычная обработка, то фиксируйте (к примеру определенная заглушка на ошибку временной неработоспособности сервера - 503) |
Файл models.yaml состоит из
components, который в свою очередь включает:schemas- моделиparameters- параметры
Пример структуры файла:
components:
schemas:
UpdatedOrderResponse:
type: object
description: Модель для обновленных полей заказа после выполнения действия над ним.
properties:
status:
$ref: "#/components/schemas/ExtendedOrderStatus"
actions:
type: array
description: |
Список действий, доступных над заказом.
Список пуст, если нет доступных действий.
items:
$ref: "#/components/schemas/OrderAction"
required:
- status
- actions
ReceiverType: # модель, которая содержит ограничения возможных значений по типу плательщика
type: string
enum: [individual, entity]
description: |
Тип плательщика:
- individual - физическое лицо
- entity - юридическое лицо
parameters: # параметры, которые можно переиспользовать в параметрах запроса
filter_type:
name: filter_type
in: query
description: |
Тип фильтра заказов пользователя:
- all - все заказы
- current - текущие
- done - выполненные
schema:
enum: ["all", "current", "done"]
type: stringКомментарий (
description) очень важная часть спецификации. Применимо как к методам, так и к моделям.
Уделяйте большое внимание этому полю и описывайте как можно более понятнее, вкладывайте контекст, логику, примеры - пишем как можно больше (в пределах разумного, конечно, описывать супер подробноuser.nameне стоит).
С помощь ключевого слова type задается тип данных. Типы могут быть следующими:
string- Строка текста.number- включает в себя и целые числа, и числа с плавающей точкой.integer- только целые числа.boolean- в логическом типе boolean представлено два возможных значения:trueиfalse.array- массив.object- объекты - коллекция пар элемент и значение.
Строка
- Длину строки можно ограничить, используя для этого minLength и maxLength.
- Ключевое слово
patternпозволяет определить шаблон регулярного выражения для строки - значения, которые могут быть использованы в строке. Для заданияpatternиспользуется синтаксис регулярного выражения из JavaScript (pattern: '^\d{3}-\d{2}-\d{4}$')."^"используется для обозначения начала строки,"$"- конца строки. Без^… $шаблон соответствует любой строке, содержащей указанное регулярное выражение. - Ключевое слово
formatиспользуется для того чтобы задать формат строки, например один из них:date(2017-07-21),date-time(2017-07-21T17:32:28Z),password,byte,binary
К примеру, для передачи файла используется:
avatar: # изображение, встроенное в JSON
description: Base64-encoded contents of the avatar
type: string
format: byteЧисла
- Чтобы указать диапазон возможных значений, можно использовать ключевая слова
minimumиmaximum(minimum ≤value≤ maximum). - Чтобы исключить граничные значения, укажите
exclusiveMinimum: trueиexclusiveMaximum: true
count:
description: Суммарное количество товаров в заказе
type: integer
example: 6
maximum: 25Массивы
- С помощью
minItemsиmaxItemsможно задавать минимальную и максимальную длину массива. Если не использоватьminItems, то массив может быть пустым. - Элементы массива описываем отдельным элементом, если они представляют собой коллекцию.
# Элементы массива отдельным элементом
actions:
description: |
Список действий, доступных над заказом.
Список пуст, если нет доступных действий.
type: array
items:
$ref: "#/components/schemas/OrderAction"
# Массив строк
categories:
description: |
id категорий товаров первого уровня, в которые входят товары данной акции
type: array
items:
type: stringОбъекты
- По умолчанию все элементы коллекции необязательные. Можно указать список обязательных элементов с помощью слова
required(можно отказаться отrequiredи прийти к тому, чтобы явно прописывать параметрамnullable: false, если поле не может быть пустым). - Коллекция также может быть вложенной и включать в себя коллекцию. В таком случае коллекцию оформляем отдельным объектом и даем на него ссылку для удобства всех членов команды.

Для описания данной информации следует создать папку common, где фиксировать общие договоренности, которые в самих методах никак не отразить. Также, можно выносить общие методы, к примеру, загрузка изображения (профиля, отзыва и тд).
Пример оформления файла common/api.yaml
openapi: 3.0.2
info:
title: "API"
version: "1.0.0"
contact:
name: Виктория Юльская
email: [email protected]
description: |
# Headers
<details>
Для определения текущего пользователя, во всех запросах может как приходить, так и передаваться кастомный хедер `UserID`.
</details>
# Авторизация
<details>
Схема авторизации онована на механизме access/refresh токенов.
При логине - сервер возвращает пару access/refresh токен.
В дальнейшей работе с сервером во всех запросах необходимо передавать в хедере `Authorization`
полученный access токен.
При его протухании - необходимо произвести обновление токенов с помощью соответствующего метода,
используя refresh токен.
При получении ошибки во время обновления токенов - необходимо закончить текущую сесию работы с сервером
и разлогинить пользователя.
</details>
# Пагинация
<details>
Проект поддерживает страничную пагинацию.
Каждый пагинируемый запрос должен url-параметрами принимать `page` и `size`,
а в теле ответа возвращать данные с информацией о порции пагинируемых данных.
- `page` отвечает за размер пачки пагинации,
- `size` отвечает за размер порции.
</details>
# Ошибки
<details>
<summary>Описание</summary>
Сервер возвращает ответ со статус кодом 400 и ошибкой в формате:
{
"code": 100,
"errorMessage": "Пользователь не найден",
"data": "85"
}
Ошибки состоят из
- специфического кода `code` для идентификации ошибки
- текста `errorMessage`, который будет отображаться на клиенте
(в силу этого вся обязанность за формирование текста ошибок ложиться на серверную часть,
что позволит обеспечить гибкость механики в целом)
- и опционального поля `data`, в котором может располагаться строка с какими-то данными,
которые клиенту следует отобразить
(Например, это может быть количество секунд, через которые можно повторно отправить смс)
</details>
<details>
<summary>Специфические коды ошибок</summary>
* `100` - BadJson, неверный формат JSON от клиента
* `103` - OTPCodeRequestTooOften, слишком частые запросы на генерацию OTP-кода, в **data** - количество секунд до разблокировки
* `104` - OTPCodeInvalid, неверный OTP-код
* `105` - SendingCodeFailed, не удалось послать OTP-код
* `106` - FileUploadingError - Ошибка при загрузке файла
* `107` - NotEnoughPoints - Недостаточно баллов для списания
* `108` - NotEnoughProducts - Товар закончился
* `120` - NameNotUnique - Товар с таким именем уже существует
* `119` - RefreshTokenFailed - Не удалось обновить токен
* `121` - OTPCodeExpired - срок жизни кода истек
* `122` - BonusesWriteoffFailed - Нельзя списать больше бонусов, чем есть у пользователя
servers:
- url: https://someaddress.com
description: TODO заглушка, требуется поправить в будущем на реальный адрес.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
paths:
/file:
post:
summary: Загрузка файла
description: Запрос на загрузку файла на сервер, используется, когда пользователь прикрепляет файлы
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: "models.yaml#/components/schemas/BinaryFile"
responses:
'200':
description: Успешный ответ с данными.
content:
application/json:
schema:
$ref: "models.yaml#/components/schemas/FileURL"
'400':
description: |
Возможные ошибки
* `106` - FileUploadingError - Ошибка при загрузке файла
content:
application/json:
schema:
$ref: "../common/models.yaml#/components/schemas/ErrorResponse"
/file/{fileUrl}:
delete:
summary: Удаление файла
parameters:
- name: fileUrl
in: path
description: Ссылка на файл
required: true
schema:
type: string
responses:
'204':
description: Файл удален- Ctrl (или CMD) - Можем посмотреть что за ref у нас в методе / моделе. Наводим на ref и зажимаем комбинацию, получаем информацию о нашей ссылке. Если кликнуть по ней, то быстро перейдем по ссылке к нашей модели, на которую ссылаемся.
- Ctrl (или CMD) + Shift + O - Позволяет найти и перейти к конкретной вкладке, либо конкретной модели / свойству.
- Ctrl (или CMD) + Shift + P - Открывает панель команд.
- Ctrl (или CMD) + P - Поиск файлов по имени
Минимальная проверка спецификации API на фичу может быть проведена путем визуализации спецификации API при помощи комбинации Alt+Shift+P. Комбинацию вызывать находясь в файле api.yaml.
Проверить что спецификация визуализируется, все параметры отверстаны, прописаны обязательные и nullable поля. Запросы и ответы также отрендерены и не отображаются ошибки.
Если не рендерится сваггер, на что обратить внимание:
Табуляция. Проверьте, что все находится на своем уровне
Ссылки. Проверьте, что все ссылки корректные и они ссылаются на существующие модели.
| Проблема с табуляцией | Все ок |
|---|---|
![]() |
![]() |
Для проверки должен быть подключен SurfGen и подключен линтинг через GitHub Actions.
Для корректной работы ветки называть feature_branchname, к примеру, чтобы у всех веток (кроме мастера) был единый префикс.
Далее при открытии PR-а, при пуше изменений и тд будет запускать проверка спеки на соответствие всего вышеописанного.
- Если проставилась зеленая галка, то все с вашей спекой ок.
- Если видим красный индикатор, то есть проблемы и их нужно исправить.
Идем на вкладку Checks и читаем логи (build). Начинаем читать все, начиная с третьей строки. Что мы видим?
- Линтер пошел парсить схему
/common/models.yaml - Зашел в объект
ErrorResponse - В параметре
dataнашел ошибку- Выдает нам описание ошибки.
Чтобы исправить ошибку мы идем в папку common -> файл models.yaml -> находим модель ErrorResponse, а в ней параметр data. Исправляем описанную линтером ошибку.
После того, как мы запушим изменения с исправлением линтер снова запустится и продолжит проверку. Исправляем до тех пор, пока не получим зеленую галку)
Основные дефолтные хэдеры:
Accept-Charset- способ клиента сказать в какой кодировке нужны данные (UTF-8,ASCII,whatever). Обычно всегда используетсяUTF-8и менять не нужно.Accept-Encoding(аналог с сервера -Content-Encoding) - то, как данные от сервера закодированы, обычно речь про алгоритм сжатия. Например,gzip.Accept-Language(аналог с сервера -Content-Language) - то, какой язык хочет получить клиент. Использовать можно для мультиязычных сервисах.Accept(аналог с сервера -Content-Type) - Формат данных которые клиент поддерживает, эти форматы называются MIME-типами. Например,application/json. Такое часто бывает при передаче файлов или когда хотим открыть файл в вебе, здесь нужно правильно установить MIME-тип.Cookies- это способ хранить состояние. Как это работает:- Сначала сервер просит клиента установить
cookies(Set-Cookie). - Клиент их отправляет серверу при обращении в хэдерах с ключом
Cookie.
- Сначала сервер просит клиента установить
Cookiesмогут использоваться для передачи токена. Не самый лучший способ, но такое может быть.
В таком случае обязательные параметры для такихcookies:
secure=truehttponly=truesamesite=strict
| Совет | Описание |
|---|---|
| Используйте kebab-case для URL | Вот пример для списка заказов.
Плохо: /systemOrders или /system_orders
Хорошо: /system-orders
|
| Используйте camelCase для параметров | Вот пример получения списка продуктов в магазине.
Плохо: /system-orders/{order_id} или /system-orders/{OrderId}
Хорошо: /system-orders/{orderId}
|
| Используйте множественное число для коллекций | Если вы хотите получить всех пользователей.
Плохо: GET /user или GET /User
Хорошо: GET /users
|
| Не используйте глаголы в URL ресурсов | Вместо этого пользуйтесь HTTP методами для описания операций.
Плохо: POST /updateuser/{userId} или GET /getusers
Хорошо: PUT /user/{userId}
|
| Пользуйтесь глаголами в URL операций | Например, если вы хотите переслать уведомление пользователю.
Хорошо: POST /alerts/245743/resend
Помните, что resend не является [CRUD](https://ru.wikipedia.org/wiki/CRUD) операцией. Наоборот, это функция, которая выполняет определённое действие на сервере. |
| Используйте camelCase для JSON свойств | Вместо этого пользуйтесь HTTP методами для описания операций.
Плохо: {
user_name: "Ванька Петров",
user_id: "1"
}Хорошо: {
userName: "Ванька Петров",
userId: "1"
} |
| Используйте простой порядковый номер для версий | И всегда указывайте его на самом верхнем уровне.
Хорошо: http://api.domain.com/v1/shops/3/products
|
| Указывайте количество ресурсов в ответе на запрос | Это свойство можно назвать total.
Плохо: {
users: [
...
], offset: 0
}Хорошо: {
users: [
...
] offset: 0,
total: 34
} |
Используйте параметры limit и offset |
И всегда указывайте его на самом верхнем уровне.
Хорошо: GET /shops?offset=5&limit=5
Потому что на фронтенде часто требуется пагинация |
| Не передавайте аутентификационные токены в URL | И всегда указывайте его на самом верхнем уровне.
Это очень плохая практика, потому что часто URL логгируются, и токен также сохранится. Плохо: GET /shops/123?token=some_kind_of_authenticaiton_token
Хорошо: Вместо этого пользуйтесь заголовками. Authorization: Bearer xxxxxx, Extra yyyyy
Помните — время жизни токена нужно ограничивать |
| Используйте HTTP методы для CRUD операций | В этом и есть их смысл.
GET: получение данных о ресурсах.
POST: создание новых ресурсов и подресурсов.
PUT: обновление существующих ресурсов.
PATCH: обновляет только определённые поля существующих ресурсов.
DELETE: удаляет ресурсы.
|
| URL должен отражать структуру вложенных ресурсов | Примеры:
GET /shops/2/products: получить список продуктов из магазина 2.
GET /shops/2/products/31: получить детали продукта 31 из магазина 2.
DELETE /shops/2/products/31: удалить продукт 31 из магазина 2.
PUT /shops/2/products/31: обновить данные о продукте 31. Используйте PUT на URL ресурса, а не коллекции.
POST /shops: создать новый магазин и вернуть данные о нём. Используйте POST на URL коллекции.
|













.png)