Как реализовать сортировку в API
Что проверяют
Понимаете ли вы, что сортировку в API выполняет база, а не Python после выборки, и что параметр сортировки от клиента это пользовательский ввод, который нужно проверять. Следом обычно спрашивают, как сортировка уживается с пагинацией.
Как отвечать
Сначала контракт, потом реализация:
- формат параметра: частый вариант
?sort=-created_at,name, где минус означает убывание, или параsortиorder. Главное, чтобы правило было одним во всём API; - белый список полей: имя из запроса сопоставляется со словарём разрешённых колонок, например
{"created_at": Item.created_at}. Неизвестное поле возвращает 400 или 422 с понятным текстом, а не 500; - сортировка на стороне БД: в SQLAlchemy это
select(Item).order_by(Item.created_at.desc()), в Djangoqueryset.order_by("-created_at"). Сортировать в памяти черезsorted()допустимо только маленький статичный список, иначе вы тянете всю таблицу ради одной страницы; - валидация средствами фреймворка: в FastAPI параметр удобно описать через
LiteralилиEnum, тогда неверное значение отсекается автоматически с кодом 422 и попадает в OpenAPI-схему. В DRF есть готовыйOrderingFilterс атрибутомordering_fields; - стабильный порядок: добавляйте уникальный тай-брейкер, обычно
id. Без него строки с одинаковымcreated_atпереставляются между запросами, и клиент видит дубли или пропуски на соседних страницах; - индексы: частую сортировку подкрепите индексом, при фильтрации составным, в порядке «колонка фильтра, колонка сортировки».
Сильный ход: упомянуть, что OFFSET на глубоких страницах деградирует, а keyset-пагинация вида WHERE (created_at, id) < (:c, :i) работает только при детерминированном порядке.
Где спотыкаются
Подставляют имя поля из запроса прямо в SQL строкой. Плейсхолдеры защищают значения, но не имена колонок, поэтому без белого списка это SQL-инъекция.
Уходят в Quick Sort и Merge Sort. Писать свой алгоритм в API никто не просит: встроенная сортировка Python устойчивая и работает за O(n log n), а в реальном сервисе сортирует СУБД.
Забывают про тай-брейкер и получают «прыгающие» записи при листании, которые потом долго ищут на стороне фронтенда.