Почему важно валидировать входные данные
Что проверяют
Понимаете ли, где проходит граница доверия, и знаете ли поведение encoding/json, из-за которого отсутствующее поле превращается в нулевое значение без единой ошибки.
Как отвечать
Снаружи приходит произвольный набор байт, а дальше по коду он уже считается доменным объектом. Валидация закрывает три задачи: не пустить внутрь данные, которые система не умеет обрабатывать, вернуть понятный ответ вместо паники или пятисотки, и не дать построить некорректное состояние, вроде отрицательного количества или срока в прошлом.
В Go есть своя специфика:
json.Unmarshalне ругается на отсутствующие поля, они получают нулевые значения. Отличить ноль от «не прислали» помогает указатель илиjson.RawMessage;- лишние поля тоже проходят молча, пока не включён
DisallowUnknownFields; - размер тела ограничивают через
http.MaxBytesReader, иначе один запрос съест память процесса; - набор правил удобно описывать тегами и собирать все ошибки полей в один ответ с кодом 400, а не отдавать первую попавшуюся.
Лучший вариант это не проверить и передать дальше, а разобрать вход в собственный тип: конструктор возвращает готовое значение или ошибку, и ниже по коду проверять уже нечего.
Где спотыкаются
Называют валидацию защитой от инъекций и межсайтового скриптинга. От инъекции защищают плейсхолдеры запроса, от скриптинга контекстное экранирование при выводе через html/template. Валидация отвечает за форму данных, а не за способ их подстановки, и подменять одно другим опасно.
Пишут свою регулярку для почты. Формат адреса сложнее любого короткого выражения: самописная проверка режет валидные адреса с плюсом или юникодом и всё равно пропускает несуществующие домены. Разумнее разбор штатным парсером адреса плюс подтверждение письмом.
Путают валидацию с проверкой прав. То, что идентификатор пришёл в правильном формате, ничего не говорит о том, принадлежит ли объект вызывающему. Проверка формата на входе и проверка доступа к ресурсу это два разных шага, и второй забывают чаще.