A collection of GraphQL custom scalars supporting cleanup, validation, and defaults via fluent api
npm install graphql-validated-typesjs
// Holds colors like FF00FF and 663399
const HexColor = new GraphQLValidatedString({
name: 'HexColor',
description: 'HexColor string'
}).toUpperCase().hex().length(6).default('000000');
`$3
There's an example of using this library with express in /example. You can run locally by doing
`
git clone https://github.com/stephenhandley/graphql-validated-types
cd graphql-validated-types
npm run example
`Usage
$3
The base class other types extend. It is an extension of GraphQLScalarType and can itself be instantiated as a custom scalar for use as a placeholder or to attach custom validators. Validators should either throw an error on invalid input, or return the the value (perhaps transformed) when it is valid. They can be chained as below and are run in the order they are added.
`js
const VowelCountButNoLetterE = new GraphQLValidatedScalar({
name: 'VowelCountButNoLetterE'
}).validator((value)=> {
if (value.match(/e/)) {
throw new Error('E is not allowed');
}
return value;
}).validator((value)=> {
let vowels = ['a', 'e', 'i', 'o', 'u'];
let count = 0;
for (let i = 0; i < value.length; i++) {
let letter = value[i];
if (vowels.indexOf(letter) !== -1) {
count++;
}
}
return count;
});let count = VowelCountButNoLetterE.parseValue('animals');
Assert.equal(count, 3);
Assert.throws(()=> {
VowelCountButNoLetterE.parseValue('forever');
}, /E is not allowed/);
`$3
#### Validation
Validation functions will throw
TypeError unless the value matches criteria#####
.length(length)
Requires string to be of specified length (if passed number) or min and/or max (if passed object)
`js
const VariableLength = new GraphQLValidatedString({
name: 'VariableLength'
}).length({min: 5, max: 10});Assert.throws(()=> {
VariableLength.parseValue('abcd');
}, /has invalid length/);
const FixedLength = new GraphQLValidatedString({
name: 'FixedLength'
}).length(8);
Assert.throws(()=> {
FixedLength.parseValue('abcde');
}, /has invalid length/);
`#####
.nonempty()
Alias for .length({min: 1})
`js
const NotEmpty = new GraphQLValidatedString({
name: 'NotEmpty'
}).nonempty();Assert.throws(()=> {
NotEmtpy.parseValue('');
}, /has invalid length/);
`#####
.regex(pattern)
Requires value to match pattern
`js
const HumanName = new GraphQLValidatedString({
name: 'HumanName'
}).regex(/([a-zA-Z]{3,30}\s*)+/);Assert.throws(()=> {
HumanName.parseValue('aa');
}, /does not match/);
`#####
.base64()
Alias for .regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/)
`js
const Image = new GraphQLValidatedString({
name: 'Image'
}).base64();Assert.throws(()=> {
Image.parseValue('=====');
}, /does not match/);
`#####
.hex()
Alias for .regex(/^[a-f0-9]+$/i)
`js
const Hex = new GraphQLValidatedString({
name: 'Hex'
}).hex();Assert.throws(()=> {
Hex.parseValue('=====');
}, /does not match/);
`#####
.alphanumeric()
Alias for .regex(/^[a-zA-Z0-9]+$/)
`js
const Username = new GraphQLValidatedString({
name: 'Username'
}).alphanumeric();Assert.throws(()=> {
Username.parseValue('!!!!!');
}, /does not match/);
`#####
.existsIn(arr)
Requires value to exist in arr
`js
const Domain = new GraphQLValidatedString({
name: 'Domain'
}).existsIn(['foo.com', 'bar.com']);Assert.throws(()=> {
Domain.parseValue('baz.com');
}, /not present in array/);
`#### Cleanup
#####
.trim()
Remove spaces from either side of string
`js
const Trimmed = new GraphQLValidatedString({
name: 'Trimmed'
}).trim();Assert.equal(Trimmed.parseValue(' abc '), 'abc');
`#####
.replace(pattern, replacement)
Replace pattern with replacement
`js
const Replace = new GraphQLValidatedString({
name: 'Replace'
}).replace(/b+/, 'b');Assert.equal(Replace.parseValue('abbbc'), 'abc');
`#####
.squish()
Trim sides and replace repeated spaces with single space
`js
const Squish = new GraphQLValidatedString({
name: 'Squish'
}).squish();Assert.equal(Squish.parseValue(' ab c'), 'ab c');
`#####
.truncate(length)
Limit string to maximum length
`js
const Truncate = new GraphQLValidatedString({
name: 'Truncate'
}).truncate(5);Assert.equal(Truncate.parseValue('abcdef'), 'abcde');
`#####
.toUpperCase()
Make string upper case
`js
let Upper = new GraphQLValidatedString({
name: 'Upper'
}).toUpperCase();Assert.equal(Upper.parseValue('abcDEF'), 'ABCDEF');
`#####
.toLowerCase()
Make string lower case
`js
let Lower = new GraphQLValidatedString({
name: 'Lower'
}).toLowerCase();Assert.equal(Upper.parseValue('ABCdef'), 'abcdef');
`$3
Extends GraphQLValidatedString and validates Email using email-regex.
`
// exact email address passes
const Email = new GraphQLValidatedEmail();// any string containing email address passes
const ContainsEmail = new GraphQLValidatedEmail().exact(false);
`$3
Extends GraphQLValidatedString and validates URL using url-regex.
`
// exact URL with protocol passes
const URL = new GraphQLValidatedURL();// any string containing URL with or without protocol passes
const ContainsURL = new GraphQLValidatedURL().exact(false).strict(false);
`$3
Extends GraphQLValidatedString and validates Phone Number using phone-regex
`
// exact phone number passes
const Phone = new GraphQLValidatedPhoneNumber();// any string containing phone number passes
const ContainsPhone = new GraphQLValidatedPhoneNumber().exact(false);
`$3
Extends GraphQLValidatedString and validates IP Address using ip-regex.
`
// validates string containing IP Address (either IPV4 or IPV6)
let IPAddress = new GraphQLValidatedIPAddress().exact(false);// validates string equal to IPV4 Address
let IPV4Address = new GraphQLValidatedIPAddress().v4();
// validates string equal to IPV6 Address
let IPV6Address = new GraphQLValidatedIPAddress().v6();
`$3
####
.min(minimum)
Require to be at least minimum
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).min(10);Assert.throws(()=> {
Count.parseValue(9);
}, /below minimum value/);
`####
.max(maximum)
Require to be at most maximum
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).max(10);Assert.throws(()=> {
Count.parseValue(11);
}, /above maximum value/);
`####
.range([minimum, maximum])
Require to be at least minimum and at most maximum
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).range([10, 20]);Assert.throws(()=> {
Count.parseValue(21);
}, /not within range/);
`####
.below(limit)
Require to be less than limit
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).below(10);Assert.throws(()=> {
Count.parseValue(10);
}, /not below limit/);
`####
.above(limit)
Require to be more than limit
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).above(10);Assert.throws(()=> {
Count.parseValue(10);
}, /not above limit/);
`####
.between([low, high])
Require to be more than low and less than high
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).between([10, 20]);Assert.throws(()=> {
Count.parseValue(10);
}, /not between limits/);
`####
.positive()
Require number to be greater than zero
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).positive();Assert.throws(()=> {
Count.parseValue(0);
}, /not positive/);
`####
.negative()
Require number to be less than zero
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).negative();Assert.throws(()=> {
Count.parseValue(0);
}, /not negative/);
`####
.nonnegative()
Require number to be zero or greater
`js
let Count = new GraphQLValidatedNumber({
name: 'Count'
}).nonnegative();Assert.throws(()=> {
Count.parseValue(-1);
}, /negative/);
`$3
Extends GraphQLValidatedNumber and requires number to be 32-bit (between -2147483648 and 2147483647) and truncates from floats to integers`js
const Integer = new GraphQLValidatedInteger({
name: 'Integer'
});Assert.equal(Integer.parseValue(10.5), 10);
`$3
Parses native JS Dates$3
Parses and formats dates using Moment.jsPrior to using, make sure
Moment is set on the constructor
`js
const Moment = require('moment');
const {GraphQLValidatedMoment} = require('graphql-validated-moment');
GraphQLValidatedMoment.Moment = Moment;
`#### Parsing
By default, uses Moment's parsing logic to handle ISO 8601, RFC 2822 Date time, and fall back to
new Date().`jsconst Time = new GraphQLValidatedMoment({
name: 'Time'
});
const now = new Date();
Assert.equal(Time.parseValue(now).valueOf(), now.getTime());
`####
.inputFormat(format)
Specifies custom input format
`js
const Time = new GraphQLValidatedMoment({
name: 'Time'
}).inputFormat('YYYY-MM-DD HH:mm Z');
let formatted = Time.parseValue('2010-10-20 4:30 +0000').format();
Assert.equal(formatted, '2010-10-19T21:30:00-07:00');
`####
.outputFormat(format)
Specifies custom output format for serialization
`js
const year = '2013';
const time = ${year}-02-08;
const Time = new GraphQLValidatedMoment({
name: 'Time'
}).outputFormat('YYYY');
const output = Time.serialize(Time.parseValue(time));
Assert.equal(output, year);
`#### Validators
#####
.before()
Requires date to be before now
`js
const tomorrow = Moment().add({day: 1});
const next_day = tomorrow.clone().add({day: 1});const Time = new GraphQLValidatedMoment({
name: 'Time'
}).before(tomorrow);
Assert.throws(()=> {
Time.parseValue(next_day);
}, /not before/);
`#####
.beforeNow()
Requires date to be before now
`js
const Time = new GraphQLValidatedMoment({
name: 'Time'
}).beforeNow();const tomorrow = Moment().add({day: 1});
Assert.throws(()=> {
Time.parseValue(tomorrow);
}, /not before/);
`#####
.after()
Requires date to be before now
`js
const tomorrow = Moment().add({day: 1});
const next_day = tomorrow.clone().add({day: 1});const Time = new GraphQLValidatedMoment({
name: 'Time'
}).after(next_day);
Assert.throws(()=> {
Time.parseValue(tomorrow);
}, /not after/);
`#####
.afterNow()
Requires date to be before now
`js
const Time = new GraphQLValidatedMoment({
name: 'Time'
}).afterNow();const yesterday = Moment().subtract({day: 1});
Assert.throws(()=> {
Time.parseValue(yesterday);
}, /not after/);
`$3
Wrapper on MongoDB's [ObjectID](). Handles parsing 24 char hex string, 12 byte string, or existing ObjectID. Serializes using .toHexStringPrior to using, make sure
ObjectID is set on the constructor
`js
const MongoDB = require('mongodb');
const {GraphQLValidatedObjectID} = require('graphql-validated-moment');
GraphQLValidatedObjectID.ObjectID = MongoDB.ObjectID;const ObjectID = new GraphQLValidatedObjectID();
const OBJECT_ID_HEX_STRING = '59b035f1485caa25a5505f2d';
const OBJECT_ID_12_BYTE = 'aaaaaaaaaaaa';
const OBJECT_ID_12_BYTE_AS_HEX = '616161616161616161616161';
let oid = ObjectID.parseValue(OBJECT_ID_HEX_STRING);
Assert.equal(oid.toHexString(), OBJECT_ID_HEX_STRING);
oid = new MongoDB.ObjectID();
Assert.equal(ObjectID.parseValue(oid), oid);
oid = ObjectID.parseValue(OBJECT_ID_12_BYTE);
Assert.equal(oid.toHexString(), OBJECT_ID_12_BYTE_AS_HEX);
Assert.equal(ObjectID.serialize(oid), OBJECT_ID_12_BYTE_AS_HEX);
`$3
Parses semver i.e. 1.0.4`