OpenAPI в FastAPI: как сохранить operationId для сгенерированного клиента

После переименования Python-функции API продолжает отвечать по прежнему URL, но генератор SDK меняет имя клиентского метода. Для пользователя интерфейс вроде бы не изменился, а код интеграции перестал собираться. operationId в OpenAPI — отдельная часть договора, которую стоит сделать явной, если вы генерируете клиент.

Путь и имя операции решают разные задачи

HTTP-клиент обращается к методу и URL. Генератор SDK дополнительно использует operationId, чтобы назвать метод в целевом языке. FastAPI умеет создавать его автоматически, но тогда изменение имени функции или пути способно изменить результат. Явный operation_id отделяет публичное имя операции от устройства Python-модуля.

Идентификаторы должны быть уникальны в схеме. Если одинаковое имя задано двум операциям, генератору придётся разрешать конфликт, а результат станет зависеть от инструмента. Выберите понятный стиль, например listRooms и getRoom, и проверяйте уникальность на всём приложении после подключения роутеров.

Проверяем настоящую схему приложения

Нужны FastAPI и HTTPX. Обработчики имеют технические Python-имена, а operation_id остаётся коротким публичным названием. Тест читает /openapi.json и проверяет две операции. Такой тест обнаруживает случайное удаление аргумента из декоратора.

Сохраните весь блок в файл и запустите Python 3.11+ в отдельном окружении с пакетами fastapi, httpx. Для моделей используется Pydantic v2; отдельный сервер для TestClient не нужен.

from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()
@app.get("/rooms", operation_id="listRooms")
def list_rooms_http_handler():
    return []

@app.get("/rooms/{room_id}", operation_id="getRoom")
def get_room_http_handler(room_id: int):
    return {"id": room_id}

with TestClient(app) as client:
    schema = client.get("/openapi.json").json()
    assert schema["paths"]["/rooms"]["get"]["operationId"] == "listRooms"
    assert schema["paths"]["/rooms/{room_id}"]["get"]["operationId"] == "getRoom"
    methods = {"get", "put", "post", "delete", "patch", "options", "head", "trace"}
    ids = [operation["operationId"] for path in schema["paths"].values()
           for method, operation in path.items() if method in methods]
    assert len(ids) == len(set(ids)) == 2
    assert client.get("/rooms/7").json() == {"id": 7}
print("stable unique operation ids:", ids)

Что ещё способен изменить SDK

Стабильное имя метода не сохраняет автоматически его аргументы и типы. Изменение обязательного query-параметра, формы тела или схемы ответа тоже влияет на сгенерированный клиент. Перед публикацией сравните OpenAPI с предыдущей версией и посмотрите, какие изменения требуют обновления интеграции.

Не обещайте совместимость только потому, что URL остался прежним. Новый обязательный заголовок или удалённое поле ответа может сломать существующий сценарий. Для важных клиентов полезен тест их реального запроса к новой версии API или сборка SDK в тестовом контуре.

Когда схема уже закэширована

FastAPI сохраняет сгенерированную схему. Настраивайте операции и подключайте роутеры до первого вызова openapi. Если вы меняете конфигурацию динамически, учитывайте этот кэш и осознанно пересоздавайте схему. В обычном приложении проще полностью собрать маршруты при старте и затем считать контракт неизменным.

В этой проверке SDK не генерируется: выполняются запросы к FastAPI и анализируется реальная OpenAPI-схема. Если команда использует конкретный генератор, добавьте отдельную проверку его вывода и сборки клиента. Тогда связь между operationId и фактическим именем метода будет подтверждена для выбранного инструмента.

Следующая практика

В открытом уроке первого приложения вы увидите автоматически построенную документацию FastAPI. Затем откройте /openapi.json и сопоставьте операции с их именами: это основа для проверки контракта сгенерированного клиента. Откройте бесплатный урок FastAPI и Swagger.

В бесплатном курсе FastAPI вы увидите, как маршруты, модели и ошибки складываются в документацию работающего API. Сохраняйте проверку схемы вместе с HTTP-тестами при каждом изменении публичного договора. Откройте программу курса.

Продолжить на практике