Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
schemaglobin
Advanced tools
Schemaglobin is a schema validator for user input written for JavaScript and TypeScript with special attention paid to TypeScript types.
npm install schemaglobin
Import schema creator functions (e.g. string()
). These functions take an options
object that configures the schema and returns an instance of the corresponding schema class.
When you have created a schema you can pass unknown values into the validate()
method to validate those values:
Invalid
, which contains a user-facing message
property describing why.This basic example shows how Schemaglobin can be used in the real world:
import { object, string, number, boolean, Invalid } from "schemaglobin";
// Create a schema that can validate the data.
const schema = object(
required: true;
props: {
"name": string({ required: true }),
"age": number({ required: true, min: 0, max: 150 }),
"status": boolean(),
}
);
// Function that runs on the server that validates input and saves it to the database.
export function myServerFunction(unsafeInput: unknown): true {
// Validate the unsafe input.
const data = schema.validate(unsafeInput);
// Note that the TypeScript type of data is:
// { name: string, age: number, status: boolean } | Invalid
// The data was invalid. Throw an error.
if (data instanceof Invalid) throw new ServerError("Invalid input: " + data.message);
// Note: Now that we've filtered out Invalid we know the type is just the expect data object.
// The data is valid. Now we can save it to the database safely.
const status = saveToDatabase(data);
// Success!
return true;
}
Is you pass an invalid value into validate()
then two things might happen: 1) If the invalid value can be trivially converted to a valid value without data loss, it will be converted and returned, or 2) An instance of Invalid
will be returned:
import { string, number, email, url, boolean, Invalid } from "schemaglobin";
// Trivial conversion.
boolean().validate("abc"); // Returns `true`
boolean().validate(""); // Returns `false`
string().validate(123); // Returns "123" string.
number().validate("123.456"); // Returns 123.456 number.
// Fully invalid values.
string().validate(true); // Returns Invalid("Must be string")
number().validate("abc"); // Returns Invalid("Must be number or null")
email().validate("abc"); // Returns Invalid("Invalid email format")
url().validate("abc"); // Returns Invalid("Invalid URL format")
With object schemas, options.props
is used to fill (and trivially convert) missing object props:
import { object, number, string } from "schemaglobin";
// Make an object schema.
const schema = object({
props: {
name: string({ value: "DEFAULT" }),
age: number(),
},
});
// Returns { name: "DEFAULT", age: 123 }
schema.validate({ age: "123" });
// Returns { name: "Dave", age: null }
schema.validate({ name: "Dave" });
Instances of Invalid
contain a string .message
property describing the issue:
const invalid = url().validate("abc");
console.error(invalid.message); // Logs "Invalid URL format"
When validating an object, it's possible the contents might be invalid. In this situation Invalid
also has a .messages
object specifying where, within the object, the data was invalid.
import { object, string, number } from "schemaglobin"
// Make an object schema with `options.props`
const schema = object({
props: {
name: string({ required: true }),
age: number({ min 0, max: 200 }),
}
});
// Validate an invalid value.
const invalid = schema.validate({ age: 900 });
console.log(invalid.message); // "Invalid format"
console.log(invalid.messages); // { name: "Required", age: "Maximum 200" }
This also works for arrays. The keys in .messages
will be numeric strings:
import { array, string } from "schemaglobin";
// Make an array schema with `options.items`
const schema = array({
items: string({ required: true }),
});
// Validate an invalid value.
const invalid = schema.validate([123, true, ""]);
console.log(invalid.message); // "Invalid format"
console.log(invalid.messages); // { "1": "Must be string", "2": "Required" }
Schemaglobin contains a bunch of different schema types you can use:
import { boolean, string, number, date, email, phone, url, key, array, object, map } from "schemaglobin";
// Create schemas.
const booleanSchema = boolean({ required: true, ...etc });
const stringSchema = string({ required: true, ...etc });
const numberSchema = number({ required: true, ...etc });
const dateSchema = date({ required: true, ...etc });
const emailSchema = email({ required: true, ...etc });
const phoneSchema = phone({ required: true, ...etc });
const urlSchema = url({ required: true, ...etc });
const keySchema = key({ required: true, ...etc });
const arraySchema = array({ required: true, ...etc });
const objectSchema = object({ required: true, ...etc });
const mapSchema = object({ required: true, ...etc });
// Successful validation.
booleanSchema.validate(true); // Returns true
stringSchema.validate("abc"); // Returns "abc"
numberSchema.validate(12345); // Returns "123"
dateSchema.validate("1995"); // Returns "1995-01-01"
emailSchema.validate("me@x.com"); // Returns "me@x.com"
phoneSchema.validate("+1234567890"); // Returns "+1234567890"
urlSchema.validate("http://x.com"); // Returns "http://x.com"
keySchema.validate("ajdk29Jak"); // Returns "ajdk29Jak"
arraySchema.validate(["a", 2, true]); // Returns ["a", 2, true]
objectSchema.validate({ a: "A" }); // Returns { a: "A" }
mapSchema.validate({ a: "A" }); // Returns { a: "A" }
// Successful validation.
stringSchema.validate(true); // Returns Invalid("Must be string")
numberSchema.validate(true); // Returns Invalid("Must be number or null")
dateSchema.validate("aaaaaaa"); // Returns Invalid("Invalid date")
emailSchema.validate("111111"); // Returns Invalid("Invalid email format")
phoneSchema.validate("aaaaaa"); // Returns Invalid("Invalid phone number")
urlSchema.validate("11111111"); // Returns Invalid("Invalid URL format")
keySchema.validate("!!!!!!!"); // Returns Invalid("Invalid key format")
arraySchema.validate(true); // Returns Invalid("Must be array")
objectSchema.validate(true); // Returns Invalid("Must be object or null")
mapSchema.validate(true); // Returns Invalid("Must be object or null")
Every schema has a default value that is used when the value is undefined
. The default value can be changed for any schema with options.value
import { string } from "schemaglobin";
const schemaWithoutDefault = string();
schemaWithDefault.validate(); // Returns ""
const schemaWithDefault = string({ value: "WOW VALUE" });
schemaWithDefault.validate(); // Returns "WOW VALUE"
schemaWithDefault.validate(undefined); // Returns "WOW VALUE"
Normally values are not required, meaning null
or ""
empty string are allowed. This can be changed with options.required
import { number } from "schemaglobin";
const optionalSchema = number({ required: false });
optionalSchema.validate(null); // Returns null.
const requiredSchema = number({ required: true });
optionalSchema.validate(null); // Returns Invalid("Required")
Schemaglobin pays special attention to the TypeScript type of values returned by validate()
, for example:
NumberSchema.validate()
number | null | Invalid
options.required
is truthy the value will never be null
(as that would be invalid) so it only returns number | Invalid
StringSchema.validate()
string | Invalid
options.options
is set it can return a more specific type, e.g. "a" | "b" | "" | Invalid
ObjectSchema.validate()
{}
options.props
is set it can return a more specific type, e.g.{ a: string, b: number }
import { object, string, number, boolean, Invalid } from "schemaglobin";
// `options.required` filters out falsy value.
const requiredNumber: number | Invalid = number({ required: true }).validate(123); // No error.
const optionalNumber: number | Invalid = number({ required: false }).validate(123); // Error `number | null | Invalid` cannot be assigned to `number | Invalid`
// Return type for StringSchema is inferred from `options.options`
const enumStringArray: "a" | "b" | Invalid = string({ options: ["a", "b"] }).validate("a"); // No error.
const enumStringObject: "a" | "b" | Invalid = string({ options: { a: "A", b: "B" } }).validate("a"); // No error.
// Return type for ObjectSchema is inferred from `options.props`
const objectSchema = object({
required: true,
props: {
num: number(),
str: string({ required: true }),
bool: boolean({ required: true }),
},
});
// Validated value has type `{ num: number | null, str: string, bool: true } | Invalid`
const obj = objectSchema.validate(undefined);
if (!(obj instanceof Invalid)) {
const num: number | null = obj.num; // No error.
const str: string = obj.str; // No error.
const bool: true = obj.bool; // No error.
}
Schemaglobin also provides the SchemaType<Schema>
and SchemaRequired<Schema>
helper type, which allow you to extract the type of a schema and whether or not it is required:
import { string } from "schemaglobin";
// Make some schemas.
const requiredStringSchema = string({ required: true });
const optionalStringSchema = string({ required: false });
const requiredEnumSchema = string({ required: true, options: ["a", "b"] });
const optionalEnumSchema = string({ required: false, options: ["a", "b"] });
// Extract the types.
type RequiredStringType = SchemaType<typeof requiredStringSchema>; // string
type OptionalStringType = SchemaType<typeof optionalStringSchema>; // string
type RequiredEnumType = SchemaType<typeof requiredEnumSchema>; // "a" | "b"
type OptionalEnumType = SchemaType<typeof optionalEnumSchema>; // "a" | "b" | ""
// Object type can be inferred from `options.props`
const objectSchema = object({ props: { str: string(), num: number() } });
type ObjectType = Schematype<typeof objectSchema>; // { str: string, num: number | null }
All schema creator functions allow the following options (and may allow others too):
options.value: any = any
- The default value of the schema which will be used if the value is undefined
options.required: boolean = false
- If true, then null
or empty values will return Invalid("Required")
options.title: string = ""
- A title for the schema (for showing in a user-facing field).options.description: string = ""
- A description for the schema (for showing in a user-facing field).options.placeholder: string = ""
- A placeholder for the schema (for showing in a user-facing field).boolean()
The boolean()
creator function creates a BooleanSchema
instance:
true
false
false
false
is an invalid value if options.required
is truthy.string()
The string()
creator function creates a StringSchema
instance:
multiline
option is true
""
empty string""
empty string""
empty string is an invalid value if options.required
is truthy.string()
also allows the following options:
options.min: number = 0
- The minimum number of characters allowed.options.max: number = null
- The maximum number of characters allowed.options.options?: string[] | { string: string }
- Explicit list of allowed values as either:
options.match: RegExp = null
- A regular expression that the string must match.options.multiline: boolean = false
- Whether the string allows newlines or notnumber()
The number()
creator function creates a NumberSchema
instance that can validate numbers:
0
zero is a valid value.null
null
is an invalid value if options.required
is truthy.number()
also allows the following options:
options.min: number = null
- The minimum number allowed.options.max: number = null
- The maximum number allowed.options.options: number[] | { number: string } = null
- Explicit list of allowed values as either:
options.step: number = null
- The step size for the the number (the value will be rounded to the closest step).date()
The date()
creator function creates a DateSchema
instance that can validate date YMD strings:
1995-10-20
new Date()
and converted to YMD strings.Date
instances and numbers are converted to YMD strings.value
, min
and max
options can be functions that return calculated values, e.g. using value: Date.now
will set the value to today's date.null
null
is an invalid value if options.required
is truthy.date()
also allows the following options:
options.min: string = null
- The minimum date allowed.options.max: string = null
- The maximum date allowed.email()
The email()
creator function creates a EmailSchema
instance that can validate email addresses:
dave@gmail.com
null
null
is an invalid value if options.required
is truthy.url()
The url()
creator function creates a UrlSchema
instance that can validate URLs:
https://x.com
or data:anything
null
null
is an invalid value if options.required
is truthydate()
also allows the following options:
options.schemes: string[] = ["http:", "https:"]
- Whitelist of allowed URL schemes.options.hosts: string[] = null
- List of allowed hostnames, e.g. ["google.com"]
options.max: number = 512
- Maximum length of a URL.phone()
The phone()
creator function creates a PhoneSchema
instance that can validate URLs:
+441234567890
null
null
is an invalid value if options.required
is truthy.key()
The key()
creator function creates a KeySchema
instance that can validate database key strings:
abc
or AAAA1234
a-zA-Z0-9
or -
hyphen.null
null
is an invalid value if options.required
is truthy.key()
also allows the following options:
options.match: RegExp = /[a-zA-Z0-9-]{1,24}/
- Format the database key must match.object()
The object()
creator function creates a ObjectSchema
instance that can validate an exact object:
{ a: 1, b: "two" }
options.props
null
null
is an invalid value if options.required
is truthy.object()
also allows the following options:
options.props: { [prop: string]: Schema }
(required) - An object explicitly specifying the type of each individual property.array()
The array()
creator function creates a ArraySchema
instance that can validate arrays and their contents:
[1,2,3]
options.items
[]
empty array.[]
empty array is an invalid value if options.required
is truthy.array()
also allows the following options:
options.min: number = null
- The minimum number of items allowed.options.max: number = null
- The maximum number of items allowed.options.items: Schema
(required) - Schema that will be used to validate the contents of the array.map()
The map()
creator function creates a MapSchema
instance that can validate an object containing a list of key: value entries:
{ a: 1, b: 2, c: 3 }
options.props
{}
empty object.{}
empty object is an invalid value if options.required
is truthy.map()
also allows the following options:
options.min: number = null
- The minimum number of items allowed.options.max: number = null
- The maximum number of items allowed.options.items: Schema
(required) - Schema that will be used to validate all properties in the object.The following static values are available as shortcuts attached to the creator functions for all simple values:
import { boolean, date, email, key, number, phone, string, url } from "schemaglobin";
// The following is equivalent to e.g. boolean({ required: true }).validate()
boolean.required.validate(true);
boolean.optional.validate(false);
date.required.validate(new Date());
date.optional.validate(null);
email.required.validate("dave@x.com");
email.optional.validate(null);
key.required.validate("abc123");
key.optional.validate(null);
number.required.validate(12345);
number.optional.validate(null);
phone.required.validate("+44123456789");
phone.optional.validate(null);
string.required.validate("AAAAA");
string.optional.validate("");
url.required.validate("https://x.com");
url.optional.validate(null);
Object/map/array schemas also provide shortcuts, but as options.props
and options.items
are required these must be passed in as the only argument:
import { object, array, map, number, string, boolean } from "schemaglobin";
// Object shortcuts accept `options.props` as an argument.
object.required({ num: number.optional }).validate({ num: 123 });
object.optional({ num: number.required }).validate(null);
// Array shortcuts accept `options.items` as an argument.
array.required(string.required).validate([1, 2, 3]);
array.optional(string.required).validate([]);
// Map shortcuts accept `options.items` as an argument.
map.required(boolean.required).validate({ a: 1, b: 2, c: 3 });
map.optional(boolean.required).validate(null);
See Releases
FAQs
Validate user-entered data.
The npm package schemaglobin receives a total of 1 weekly downloads. As such, schemaglobin popularity was classified as not popular.
We found that schemaglobin demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.