Документация потокового 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 и т.д.). В документации обязательно перечислите все возможные коды и их значения.

    Часто задаваемые вопросы