Hajime, the duck guy

Forms kata
On this page
Level: Important

Simple validation

A few basic input validation functions in plain JavaScript

The way of kata

Kata is an exercise for muscle memory. It's not intended to fill your brain with information but train your fingers to react. The information is there to give you the why, but your fingers need to learn the how.

The material on this page is presented in a specific order — from least specific to highly technical. You will learn the most by jumping in as soon as you have some idea of what you should do. Once you're done, read the rest of the material and check your solution.

All katas are designed to be doable without using 3rd party libraries (and, in fact, the point is to also learn how to do what these libraries do).

To make the best of katas, observe the following rules.

  • Don't rush.
  • When stuck, take a break and do something unrelated.
  • Do not copy/paste code. Always retype everything.
  • Do not use AI tools to generate code.
  • Try to do something that wasn't in the instructions, experiment.
  • Repeat the kata from time to time, even if you think you've got it.
  • You have mastered the kata once you are able to complete it without thinking too much.

Remember, the goal is not to get it done, but to get some practice.

Introduction

In this exercise, you will write a series of functions for validating user input. Input validation is a critical element of any program that deals with user input. It serves the purpose of both guiding the user towards successful completion of forms, and it also defends the application against intentionally malformed input that is designed to compromise your program. Keep this in mind while doing this exercise.

Skills you will acquire

  • User input validation

Objective

Write functions to validate the following:

  • Field is required and value is specified
  • Field contains a valid email address
  • Field contains a valid date in YYYY-MM-DD format.
  • Field contains at least N characters
  • Field contains at most N characters
  • Field contains a numeric value (either an integer or a decimal number)
  • Field contains a value that satisfies any combination of other validators

The validator should return a string that says what went wrong. If there is no error, it should return an empty string.

Check your solution

  • Catch fields that are blank
  • Catch fields that only comprise of whitespace as blank
  • Catch fields that are filled in but aren't a valid email address
  • Catch invalid month and date numbers in dates such as 2024-44-99
  • Catch fields that are filled in but have more characters than specified
  • Catch fields that are filled in but have less characters than specified
  • Ignore trailing and leading whitespace when counting characters for length limits
  • Correctly count emoji or characters written in some non-English languages (e.g., 🦆 as 1)
  • Catch invalid numeric values such as 1.2.3 or .32
  • When combining multiple validators, the the first failing validation is reported
  • When combining multiple validators

Tools

Keep in mind

All inputs are strings.

A validator could be written as a function that takes the input as its only argument and returns an empty string when there is no error, or an error message specific to what it validates.

When you are deciding what the error message should say, consider two possible patterns:

  1. The string could represent a message intended for the end user
  2. The string could represent an identifier that can be later mapped to a message for the end user

The second pattern is slightly more complex, but it gives the interface code more flexibility in how it will report the error (e.g., the same constraint may have different meanings depending on the context).

Validators cannot validate anything that is validated by another validator. For example, an email validator cannot also validate that field is missing a value.

Some validators have parameters (e.g., "contains at least N characters" has "N" as a parameter), and some do not.

A function that combines multiple validators can be seen as a validator that has other validators as parameters.

A standards-compliant email address may include ludicrous things that are not normally seen as an email address in practical everyday use. Research various ways to validate email addresses and pick a pragmatic approach.

When testing that something is in a valid format, do not forget that just because it can be used as an input in some cases, it doesn't mean it's valid. For example:

parseFloat('2a') // => 2

In the example, '2a' is not a valid number, but parseFloat() will let you treat it as a valid input. Your validator should fail this kind of input. In many cases, using regular expressions is the right approach to test input validity.

Try also playing with other ideas such as making each validator a class.

Reading list

Hints & spoilers

Hint: Implementing parametrized validators
A validator that has a parameter can be thought of as a function that creates a validator function. For example:
function validateMaxLength(length) {
  return function (value) {
          // This is the actual validator function
  }
}

The example shows what is commonly known as 'currying'. The outer function's sole purpose is to capture and "hold onto" the length parameter for the inner one. The inner function is returned by the other function but keeps access to the length variable (parameters are variables) even after it is returned (this phenomenon is called 'closure').

Want more?

Back to top