Документация потокового API для аудио: WebSocket и gRPC
При создании нового эндпоинта, который принимает аудиопоток от фронта, передаёт его в сервис расшифровки по gRPC и возвращает текст чанками, встаёт вопрос: как правильно описать такой протокол в документации? Рассмотрим два популярных стандарта - OpenAPI и AsyncAPI - и дадим практические рекомендации.
Какой стандарт выбрать: OpenAPI или AsyncAPI?
OpenAPI (бывший Swagger) идеально подходит для синхронных REST-запросов. Однако для потоковой передачи данных (WebSocket, Server-Sent Events) он менее пригоден: в OpenAPI 3.0 появилась поддержка WebSocket, но она ограничена. AsyncAPI создан именно для асинхронных протоколов: WebSocket, gRPC, Kafka и др. Он позволяет описать события, каналы, а также потоковый ввод-вывод чанками. Если ваш сервис уже использует OpenAPI для синхронных эндпоинтов, можно добавить AsyncAPI-спецификацию для нового потокового эндпоинта - это стандартная практика.
Версионирование эндпоинта для WebSocket
Версионирование для WebSocket и gRPC обычно делается через URL-путь (например, /v1/audio/transcribe) или через заголовки. В AsyncAPI версия указывается в корне документа (asyncapi: '2.6.0'), а для отдельных каналов можно добавить свой параметр version. Рекомендуется придерживаться семантического версионирования (MAJOR.MINOR.PATCH) и отражать изменения в спецификации.
Как описать потоковый ввод и вывод чанками?
В AsyncAPI для описания потока данных используется объект message с указанием contentType (например, application/octet-stream для аудио). Для чанков текста можно определить несколько типов сообщений: AudioChunk (входящий) и TextChunk (исходящий). Внутри канала WebSocket эти сообщения будут следовать друг за другом. Пример:
channels:
/audio/transcribe:
subscribe:
message:
$ref: '#/components/messages/TextChunk'
publish:
message:
$ref: '#/components/messages/AudioChunk'Разделение на установку соединения и обмен данными
Да, в AsyncAPI есть чёткое разделение: установка соединения описывается в разделе servers (адрес, порт, протокол), а внутренний обмен - в channels. Для WebSocket можно указать bindings с настройками рукопожатия. Для gRPC - использовать отдельный протокол, но AsyncAPI позволяет описать и его через bindings для gRPC.
Выбор пути эндпоинта и правила для REST/RPC
К путям WebSocket и gRPC можно применять те же принципы, что и к REST: использовать существительные во множественном числе, избегать глаголов, группировать по ресурсам. Например: /v1/audio/transcribe - понятно и предсказуемо. Для gRPC путь задаётся именем сервиса и методом (например, /AudioService/Transcribe). Версионирование через префикс /v1/ - хорошая практика.
Коды ошибок и успешные статусы
Для WebSocket используйте стандартные коды закрытия (1000 - нормальное закрытие, 1011 - внутренняя ошибка сервера). В AsyncAPI можно описать возможные ошибки как отдельные сообщения (Error) с полями code и message. Для gRPC - стандартные gRPC-статусы (OK, INVALID_ARGUMENT, INTERNAL и т.д.). В документации обязательно перечислите все возможные коды и их значения.