npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graphql-validated-types

v2.11.0

Published

A collection of GraphQL custom scalars supporting cleanup, validation, and defaults via fluent api

Downloads

1,855

Readme

graphql-validated-types

A collection of GraphQL custom scalars supporting cleanup, validation, and defaults via fluent api.

Example

Hex colors

// Holds colors like `FF00FF` and `663399`
const HexColor = new GraphQLValidatedString({
  name: 'HexColor',
  description: 'HexColor string'
}).toUpperCase().hex().length(6).default('000000');

Example Project

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

GraphQLValidatedScalar

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.

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/);

GraphQLValidatedString

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)

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})

const NotEmpty = new GraphQLValidatedString({
  name: 'NotEmpty'
}).nonempty();

Assert.throws(()=> {
  NotEmtpy.parseValue('');
}, /has invalid length/);
.regex(pattern)

Requires value to match pattern

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}=)?$/)

const Image = new GraphQLValidatedString({
  name: 'Image'
}).base64();

Assert.throws(()=> {
  Image.parseValue('=====');
}, /does not match/);
.hex()

Alias for .regex(/^[a-f0-9]+$/i)

const Hex = new GraphQLValidatedString({
  name: 'Hex'
}).hex();

Assert.throws(()=> {
  Hex.parseValue('=====');
}, /does not match/);
.alphanumeric()

Alias for .regex(/^[a-zA-Z0-9]+$/)

const Username = new GraphQLValidatedString({
  name: 'Username'
}).alphanumeric();

Assert.throws(()=> {
  Username.parseValue('!!!!!');
}, /does not match/);
.existsIn(arr)

Requires value to exist in arr

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

const Trimmed = new GraphQLValidatedString({
  name: 'Trimmed'
}).trim();

Assert.equal(Trimmed.parseValue(' abc '), 'abc');
.replace(pattern, replacement)

Replace pattern with replacement

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

const Squish = new GraphQLValidatedString({
  name: 'Squish'
}).squish();

Assert.equal(Squish.parseValue(' ab  c'), 'ab c');
.truncate(length)

Limit string to maximum length

const Truncate = new GraphQLValidatedString({
  name: 'Truncate'
}).truncate(5);

Assert.equal(Truncate.parseValue('abcdef'), 'abcde');
.toUpperCase()

Make string upper case

let Upper = new GraphQLValidatedString({
  name: 'Upper'
}).toUpperCase();

Assert.equal(Upper.parseValue('abcDEF'), 'ABCDEF');
.toLowerCase()

Make string lower case

let Lower = new GraphQLValidatedString({
  name: 'Lower'
}).toLowerCase();

Assert.equal(Upper.parseValue('ABCdef'), 'abcdef');

GraphQLValidatedEmail

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);

GraphQLValidatedURL

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);

GraphQLValidatedPhoneNumber

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);

GraphQLValidatedIPAddress

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();

GraphQLValidatedNumber

.min(minimum)

Require to be at least minimum

let Count = new GraphQLValidatedNumber({
  name: 'Count'
}).min(10);

Assert.throws(()=> {
  Count.parseValue(9);
}, /below minimum value/);

.max(maximum)

Require to be at most maximum

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

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

let Count = new GraphQLValidatedNumber({
  name: 'Count'
}).below(10);

Assert.throws(()=> {
  Count.parseValue(10);
}, /not below limit/);

.above(limit)

Require to be more than limit

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

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

let Count = new GraphQLValidatedNumber({
  name: 'Count'
}).positive();

Assert.throws(()=> {
  Count.parseValue(0);
}, /not positive/);

.negative()

Require number to be less than zero

let Count = new GraphQLValidatedNumber({
  name: 'Count'
}).negative();

Assert.throws(()=> {
  Count.parseValue(0);
}, /not negative/);

.nonnegative()

Require number to be zero or greater

let Count = new GraphQLValidatedNumber({
  name: 'Count'
}).nonnegative();

Assert.throws(()=> {
  Count.parseValue(-1);
}, /negative/);

GraphQLValidatedInteger

Extends GraphQLValidatedNumber and requires number to be 32-bit (between -2147483648 and 2147483647) and truncates from floats to integers

const Integer = new GraphQLValidatedInteger({
  name: 'Integer'
});

Assert.equal(Integer.parseValue(10.5), 10);

GraphQLValidatedDate

Parses native JS Dates

GraphQLValidatedMoment

Parses and formats dates using Moment.js

Prior to using, make sure Moment is set on the constructor

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(<input>).


const Time = new GraphQLValidatedMoment({
  name: 'Time'
});
const now = new Date();
Assert.equal(Time.parseValue(now).valueOf(), now.getTime());

.inputFormat(format)

Specifies custom input format

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

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

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

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

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

const Time = new GraphQLValidatedMoment({
  name: 'Time'
}).afterNow();

const yesterday = Moment().subtract({day: 1});
Assert.throws(()=> {
  Time.parseValue(yesterday);
}, /not after/);

GraphQLValidatedObjectID

Wrapper on MongoDB's ObjectID. Handles parsing 24 char hex string, 12 byte string, or existing ObjectID. Serializes using .toHexString

Prior to using, make sure ObjectID is set on the constructor

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);

GraphQLValidatedSemver

Parses semver i.e. 1.0.4

TODO

  • support for array and object type validation?

Notes

This is based on aspects adapted from the following

  • https://github.com/graphql/graphql-js/blob/master/src/type/scalars.js
  • http://dev.apollodata.com/tools/graphql-tools/scalars.html
  • https://github.com/li-kai/graphql-scalar-types
  • https://github.com/stylesuxx/graphql-custom-types
  • https://github.com/mugli/learning-graphql/blob/master/7.%20Deep%20Dive%20into%20GraphQL%20Type%20System.md
  • https://github.com/xpepermint/graphql-type-factory