Как найти и войти в театр "версионирование API" я описал в предыдущем материале — как организовать документирование, роутинг, реализацию и устаревание версии. А вот что происходит дальше — пока не рассказал. Ведь в моменты, когда:
- Меняются модели
- Меняются нефункциональные требования
Мы слышим второй звонок и все куда-то начинают уходить. А именно здесь и начинается интересная часть версионирования, а не в моменте "добавь опциональное поле".
Версионирование API при изменении модели
Классический API — принять какой-то JSON, на его основе извлечь нужные данные из БД и отдать другой JSON. И если версионирование алгоритма преобразования одного JSON в другой не вызывает особых проблем (только написание кода), то при работе с данными из БД могут быть сюрпризы. Между старой и новой версиями могли происходить изменения:
- Поменялось название таблиц/модели
- Поменялось название поля
- Поменялся формат поля (например, был любой int, стал enum на базе int)
- Добавили/удалили поле
- Перестали писать данные в одно поле, стали писать в новое
- Поменялись условия на уникальность, ограничения данных, чтобы не писать мусор в БД
Я ещё расскажу, как стоит вносить изменения в БД, чтобы снизить объём будущей боли, а сейчас скажу, что в Django принято делать это при помощи миграций.
Можно продолжать еще, но и этого достаточно для иллюстрации — нельзя гарантировать, что даже существующая версия не сломается "просто так". И как быть, если всё может сломаться "само"?
Разумеется, если данные были удалены полностью — фреймворк не решит это. В остальных случаях — попытаться можно.
В нашем арсенале есть несколько основных мест, куда поместить различие версий моделей:
- Модели, добавив/убрав property методы
- Сериализаторы, создав на каждую версию свой класс
- View, разделив логику по разным местам
И рекомендуется различие версий моделей класть именно в сериализаторы. Потому что именно на этом уровне идет превращение данных из формата "AS IS" в формат "TO BE".