Validation Snippets for Go
Over the past few years I've built up a collection of snippets for validating inputs in Go. There's nothing new or groundbreaking here, but hopefully they might save you some time.
The snippets assume that the data to validate is stored as strings in r.Form
, but the principles are the same no matter where the data has come from.
- Required inputs
- Blank text
- Min and max length (bytes)
- Min and max length (number of characters)
- Starts with, ends with and contains
- Matches regular expression pattern
- Unicode character range
- Email validation
- URL validation
- Integers
- Floats
- Date
- Datetime-local
- Radio, Select and Datalist (one-in-set)
- Checkboxes (many-in-set)
- Single checkbox
Required inputs
If you have the HTML form:
You can verify that a value for the "foo"
field has been submitted with:
For checkbox and select inputs this will ensure that at least one item has been checked.
Blank text
If you have the HTML form:
You can verify that a value for the "foo"
field isn't blank (i.e. contains whitespace only) with the strings.TrimSpace
function:
Min and max length (bytes)
If you have the HTML form:
You can verify that the "foo"
field contains a certain number of bytes with the builtin len
function:
Min and max length (number of characters)
If you have the HTML form:
You can verify that the "foo"
field contains a certain number of characters with the utf8.RuneCountInString
function. This is subtly different to checking the number of bytes. For example, the string "Zoë"
contains 3 characters but is 4 bytes long because of the accented character.
Starts with, ends with and contains
If you have the HTML form:
You can verify that the "foo"
field starts with, ends with, or contains a particular string using the functions in the strings
package:
Matches regular expression pattern
If you have the HTML form:
You can verify that the "foo"
field matches a particular regular expression using the regexp
package. For example, to check that it matches the pattern ^[a-z]{4}\.[0-9]{2}$
(four lowercase letters followed by a period and two digits):
Note that because the dot character has a special meaning in regular expressions, we escaped it using the \
character so it is interpreted as a literal period character instead. In the example above we also used a raw string for the regular expression. If you use an interpreted string (i.e. a string surrounded by double quotes), you need to escape the backslash too because that's the escape character for interpreted strings. So you would need to write:
If you're not familiar with regular expressions then this guide from Mozilla is a good explanation.
Unicode character range
If you have the HTML form:
You can verify that the "foo"
field only contains characters in a certain unicode range using the regexp
package. For example, to check that it contains only Cyrillic characters in the two unicode blocks 0400 - 04FF (Cyrillic) and 0500 - 052F (Cyrillic Supplementary):
Email validation
If you have the HTML form:
You can sanity check that the "foo"
field contains an email address using the regexp
package. Choosing a regular expression to use for email validation is a contentious topic, but as a starting point I would suggest the pattern recommended by the W3C and Web Hypertext Application Technology Working Group.
In addition, the email addresses have a practical limit of 254 bytes. Putting those together, a decent sanity check is:
Note that we have to use an interpreted string for the regular expression because it contains a backtick character (which means we can't use a raw string).
URL validation
If you have the HTML form:
You can verify that the "foo"
field contains a valid URL by first parsing it with the url.Parse
function. This will take a URL string, break it into it's component pieces, and store it as a url.URL struct. You can then sanity check the component pieces as necessary.
For instance, to check that a URL is absolute (i.e has both a scheme and host) and that the scheme is either http or https:
Integers
If you have the HTML form:
You can verify that the"foo"
field contains an integer by parsing it with the strconv.Atoi
function. You can then sanity check the integer as necessary.
For instance, to check that an integer is a multiple of 5 between 0 and 100:
Floats
If you have the HTML form:
You can verify that the "foo"
field contains an integer by parsing it with the strconv.ParseFloat
function. You can then sanity check the float as necessary.
For instance, to check that an float is a between 0 and 1:
Date
If you have the HTML form:
You can verify that the "foo"
field contains a valid date by parsing it with the time.Parse
function. It will return an error if the date is not real: any day of month larger than 31 is rejected, as is February 29 in non-leap years, February 30, February 31, April 31, June 31, September 31, and November 31.
If you're not familiar with time.Parse
, it converts strings with a given format into a time.Time object. You specify what the format is by passing the reference time (Mon Jan 2 15:04:05 -0700 MST 2006
) as the first parameter, laid-out in the format you want. If you are expecting a date in the format YYYY-MM-DD
then the reference time is 2006-01-02
.
You can then use the various functions in the time
package to sanity check the date as necessary.
For instance, to check that an date is valid and between 2017-01-01 and 2017-12-31:
Datetime-local
If you have the HTML form:
You can verify that the "foo"
field contains a valid datetime for a specific location by parsing it with the time.ParseInLocation
function. This will return an error if the date is not real: any day of month larger than 31 is rejected, as is February 29 in non-leap years, February 30, February 31, April 31, June 31, September 31, and November 31.
For instance, to check that an datetime for the "Europe/Vienna" timezone is valid and between 2017-01-01 00:00 and 2017-12-31 23:59:
The time zone database needed by LoadLocation
may not be present on all systems, especially non-Unix systems. LoadLocation
looks in the directory or uncompressed zip file named by the ZONEINFO environment variable, if any, then looks in known installation locations on Unix systems, and finally looks in $GOROOT/lib/time/zoneinfo.zip
.
Radio, Select and Datalist (one-in-a-set) validation
If you have the HTML form:
You can check that the submitted value for the "foo"
field is one of a known set like this:
Checkboxes (many-in-a-set) validation
If you have the HTML form:
To validate these, and make sure that all values sent by the form are either
wibble
, wobble
or wubble
, we need to access the underlying form data directly and range over each value:
You can check that the submitted values for the "foo"
field are part of a known set like this:
Single checkboxes
Sometimes you might have a single checkbox, and you want to verify that it has been checked. A common example is an "I accept the terms" checkbox on a form.
If you have the HTML form:
You can verify that it has been checked like this: