Should we validate method arguments in JavaScript API's?

You have the right to decide whether to make a "defensive" vs. a "contractual" API. In many cases, reading the manual of a library can make it clear to it's user that he should provide arguments of this or that type that obey these and those constraints.

If you intend to make a very intuitive, user friendly, API, it would be nice to validate your arguments, at least in debug mode. However, validation costs time (and source code => space), so it may also be nice to leave it out.

It's up to you.


Validate as much as you can and print useful error messages which help people to track down problems quickly and easily.

Quote this validation code with some special comments (like //+++VALIDATE and //--VALIDATE) so you can easily remove it with a tool for a high-speed, compressed production version.


Thanks for the detailed answers.

Below is my solution - a utility object for validations that can easily be extended to validate basically anything... The code is still short enough so that I dont need to parse it out in production.

WL.Validators = {

/*
 * Validates each argument in the array with the matching validator.
 * @Param array - a JavaScript array.
 * @Param validators - an array of validators - a validator can be a function or 
 *                     a simple JavaScript type (string).
 */
validateArray : function (array, validators){
    if (! WL.Utils.isDevelopmentMode()){
        return;
    }
    for (var i = 0; i < array.length; ++i ){            
        WL.Validators.validateArgument(array[i], validators[i]);
    }
},

/*
 * Validates a single argument.
 * @Param arg - an argument of any type.
 * @Param validator - a function or a simple JavaScript type (string).
 */
validateArgument : function (arg, validator){
    switch (typeof validator){
        // Case validation function.
        case 'function':
            validator.call(this, arg);
            break;              
        // Case direct type. 
        case 'string':
            if (typeof arg !== validator){
                throw new Error("Invalid argument '" + Object.toJSON(arg) + "' expected type " + validator);
            }
            break;
    }           
}, 

/*
 * Validates that each option attribute in the given options has a valid name and type.
 * @Param options - the options to validate.
 * @Param validOptions - the valid options hash with their validators:
 * validOptions = {
 *     onSuccess : 'function',
 *     timeout : function(value){...}
 * }
 */
validateOptions : function (validOptions, options){
    if (! WL.Utils.isDevelopmentMode() || typeof options === 'undefined'){
        return;
    }
    for (var att in options){
        if (! validOptions[att]){
            throw new Error("Invalid options attribute '" + att + "', valid attributes: " + Object.toJSON(validOptions));
        }
        try {
            WL.Validators.validateArgument(options[att], validOptions[att]);
        }
        catch (e){
            throw new Error("Invalid options attribute '" + att + "'");
        }
    }   
},

};

Heres a few examples of how I use it:

isUserAuthenticated : function(realm) {
WL.Validators.validateArgument(realm, 'string');



getLocation: function(options) {            
    WL.Validators.validateOptions{
        onSuccess: 'function', 
        onFailure: 'function'}, options);


makeRequest : function(url, options) {
    WL.Validators.validateArray(arguments, ['string', 
        WL.Validators.validateOptions.carry({
        onSuccess : 'function', 
        onFailure : 'function',
        timeout   : 'number'})]);