Какие требования к валидации числового значения для поля пополнения баланса?
Что проверяют
Понимаете ли вы, что сумма в платёжном сценарии это деньги, а не просто «число больше нуля», и где у Python тут подводные камни. Следом обычно спрашивают, что будет, если один и тот же запрос на пополнение придёт дважды.
Как отвечать
Разложите проверки по слоям:
- тип:
Decimalили целое число копеек, но неfloat.0.1 + 0.2вfloatне равно0.3, и на округлениях теряются копейки. Сумму лучше принимать строкой и сразу превращать вDecimal; - конечность:
Decimal("NaN")иDecimal("Infinity")парсятся без ошибки, их отсекаетis_finite(). Как с ними обходится ваша библиотека валидации, проверьте тестом; - знак и границы: строго больше нуля, минимум и максимум задают бизнес и лимиты платёжного провайдера;
- точность: не больше двух знаков после запятой для рубля. Сумму
10.005лучше отклонить, чем молча округлить; - формат ввода: пробелы, запятая вместо точки, экспонента
1e3, пустая строка. Решите явно, что нормализуете, а что отклоняете.
В коде это описывается декларативно. В Pydantic v2 поле вида Annotated[Decimal, Field(gt=0, le=100000, max_digits=12, decimal_places=2)], в DRF serializers.DecimalField(max_digits=12, decimal_places=2, min_value=...), в модели Django DecimalField с MinValueValidator. В базе колонка numeric(12, 2) и CHECK (amount > 0) как последний рубеж.
Дальше выйдите за пределы поля. Проверка на фронтенде это удобство, решает только сервер. Деньги зачисляются по подтверждению провайдера (вебхук с проверкой подписи), а не по сумме из запроса клиента. Повторы гасит ключ идемпотентности, а баланс меняется атомарно: UPDATE ... SET balance = balance + %s или select_for_update() внутри транзакции.
Где спотыкаются
Проверяют isinstance(value, (int, float)). Во-первых, это пропускает float, во-вторых, проходит и True, потому что bool в Python наследник int.
Ограничиваются проверкой в браузере. Запрос к API можно отправить в обход интерфейса с любым телом.
Забывают про повторную отправку: двойной клик или ретрай клиента зачисляет сумму дважды, если нет идемпотентности и уникального ключа операции.