Поле даты в HTML-форме и пакет «express-validator»

Mar 04, 2022 17:53

Начало: « MDN Web Docs: учебник по Express, ч.6-2: форма для создания нового автора».

В предыдущем посте я реализовал страницу динамического сайта (веб-приложения) с HTML-формой для ввода пользователем данных об авторе книг. Веб-приложение построено на базе веб-фреймворка «Express» и работает в рамках среды выполнения «Node.js». Код функции-контроллера и шаблона страницы я взял из руководства по веб-фреймворку «Express» с обучающего сайта «MDN Web Docs».

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

Поле даты в HTML-форме

Чтобы понять причину ошибки, я решил немного углубиться в работу поля с датой HTML-формы. Тут подробнее:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date

В современных браузерах это поле содержит значение типа «DOMString». Этот тип соответствует строкам в языке JavaScript. Поле с датой в HTML-форме может содержать строку только в формате «yyyy-mm-dd» или оно может содержать пустую строку. Информация о времени в поле с датой не содержится.

Как это сочетается с тем, что на странице нашего сайта дата в этом поле отображается в формате «dd-mm-yyyy»? Дело в том, что браузер отображает значение из поля с датой в том формате, который указан в настройках браузера. Вообще, браузер может отображать значение из этого поля в разных форматах, но хранится значение поля именно в формате «yyyy-mm-dd».

Если мы попытаемся из скрипта присвоить полю с датой значение в формате, чем-то отличающемся от указанного, то в поле с датой запишется пустая строка. Примеры таких присвоений (это фрагмент HTML-страницы):

Что это за волшебный формат такой? Используемый в поле с датой формат даты соответствует стандарту «ISO 8601». Тут подробнее:

https://ru.wikipedia.org/wiki/ISO_8601

Этот стандарт появился в 1988 году и заменил ряд стандартов о дате и времени, действовавших до него. С 1988 года у этого стандарта было множество версий с обновлениями. Так что под названием «ISO 8601» подразумевают целый ряд версий этого стандарта. Главный принцип стандарта такой: при указании даты-времени сначала указываются более значимые величины, потом менее значимые. То есть в нашем случае сначала (слева) указывается год, потом месяц, затем день. Стандарт «ISO 8601» включает еще и время, но в нашем случае мы используем только часть стандарта, касающуюся даты (наше поле, как уже было указано выше, не содержит информацию о времени).

Стандарт требует, чтобы номер года обязательно указывался в полном виде, а одноцифровые месяцы и дни обязательно указывались с ведущими нулями. Разделитель года, месяца и дня должен быть дефисом (по стандарту присутствие дефиса не обязательно, но для поля с датой HTML-формы этот разделитель обязателен).

Валидация поля с датой и пакет «express-validator»

В современных браузерах валидация поля с датой обеспечивается по умолчанию со стороны клиента (браузера). Пользователь просто никак не сможет ввести дату в это поле в неправильном формате.

Если пользователь введет одноцифровой месяц или дату, браузер сам дополнит их ведущими нулями. Если пользователь введет короткий год из двух цифр, например, «91», то браузер посчитает это годом «0091» и дополнит ведущими нулями. Так что, если пользователь хочет ввести год «1991», то ему придется ввести все четыре цифры этого года.

Пользователь может ввести несуществующую дату, например, 29 февраля 2022 года. Но отправить HTML-форму с такой датой в поле для даты браузер не даст, показав ошибку.

То есть валидация со стороны веб-сервера уже не требуется? На самом деле, требуется. Данные могут быть отправлены на веб-сервер с устаревшего браузера или от злоумышленника, который таким образом пытается нарушить работу веб-приложения.

Что с устаревшими браузерами? Например, в браузере «Internet Explorer» поле с датой «деградирует» до обычного текстового поля, в которое можно ввести любой текст.

Валидацию можно сделать и самостоятельно, но в нашем веб-приложении для этого используется пакет «express-validator». Тут подробнее:

https://express-validator.github.io

Вот как выглядит валидация поля с датой в нашем веб-приложении:

body('date_of_birth', 'Неправильная дата рождения').optional({ checkFalsy: true }).isISO8601().toDate()

Валидация и очистка, как тут видно, строится цепочками методов. В эти цепочки можно добавлять в терминах этого пакета «стандартные» валидаторы или очистители (санитайзеры) и добавочные. Пакет «express-validator» построен на следующем пакете:

https://github.com/validatorjs/validator.js

«Стандартные» валидаторы и очистители (санитайзеры) берутся из него. В нашем случае у нас в цепочке есть добавочный валидатор «optional», стандартный валидатор «isISO8601» и стандартный очиститель (санитайзер) «toDate».

Для проверки полученного веб-приложением строкового значения из HTML-формы, по идее, в этом случае достаточно было бы валидатора «isISO8601». Этот валидатор проверяет, является ли полученное строковое значение строковым значением, представляющим дату в формате, требуемом стандартом «ISO 8601», как описывалось выше. (Надо понимать, что этот валидатор пропустит как валидные значения вроде «2022», «2022-03» и так далее. Эти значения удовлетворяют требованиям стандарта «ISO 8601», но не подпадают под нужный для поля с датой формат «yyyy-mm-dd».)

Однако, если в нашей цепочке будет только валидатор «isISO8601», то поле с не введенной датой тоже будет посчитано этим валидатором за ошибку. А в нашей HTML-форме это поле с датой считается необязательным для заполнения. Чтобы учесть этот момент, в цепочку вставлен валидатор «optional» с параметром «{ checkFalsy: true }». Этот валидатор разрешает не выполнять валидацию, если в нашем поле с датой передано пустое значение. Таким образом, при наличии этого валидатора незаполненное поле с датой не вызовет ошибки при валидации.

Что делает очиститель (санитайзер) «toDate»? Он преобразует строковое значение, полученное веб-приложением, во встроенный объект «Date» языка JavaScript.

Я так и не понял, зачем в этом месте нашему веб-приложению нужен этот санитайзер. В нашем веб-приложении мы нигде далее на данной странице сайта не работаем с этой датой как датой в языке JavaScript. СУБД «MongoDB» успешно принимает строковое значение с датой в формате «yyyy-mm-dd». (СУБД «MongoDB» успешно принимает даже неполные даты вида «2022» или вида «2022-03», самостоятельно дополняя их до полных.)

А ведь именно этот санитайзер и является причиной ошибки, которую я ищу! После указанного приобразования наше веб-приложение пытается снова записать полученный объект в поле с датой HTML-формы и, понятно, ничего не получается, так как для записи требуется строковое значение формата «yyyy-mm-dd», как было описано в начале поста.

Для исправления ошибки можно вообще убрать санитайзер из цепочки валидации, либо при перезагрузке страницы с HTML-формой преобразовывать дату обратно в строку формата «yyyy-mm-dd». Я выбрал первый вариант:

body('date_of_birth', 'Неправильная дата рождения').optional({ checkFalsy: true }).isISO8601()

Теперь при перезагрузке данной страницы сайта с ошибками введенная ранее в этом поле дата сохраняется.

Инструмент, Образование, Сайтостроение, Программирование

Previous post Next post
Up