Skip to content

Repository files navigation

node-graphql-constraint-lambda

Build Statusnpm moduleConventional Commits

GraphQL constraint directive written in functional programming style. This directive provides declarative validation of GraphQL arguments.

Install

yarn add node-graphql-constraint-lambda
# or
npm install node-graphql-constraint-lambda

Usage

Example GraphQL Schema:

typeQuery {
createUser (
name: String!@constraint(minLength: 5, maxLength: 40)
emailAddr: String@constraint(format: "email")
otherEmailAddr: String@constraint(format: "email", differsFrom: "emailAddr")
age: Int@constraint(min: 18)
): User
}

Use the constraint from your code:

// when using es6 modulesimport{constraint}from'node-graphql-constraint-lambda'// when using commonjsconst{ constraint }=require('node-graphql-constraint-lambda')// ... initialize your typeDefs and resolvers here ...constserver=newGraphQLServer({
typeDefs,
resolvers,schemaDirectives: {
constraint
}// ... additional graphql server config})// ... start your server

You may need to declare the directive in the schema:

directive@constraint(
minLength: IntmaxLength: IntstartsWith: StringendsWith: Stringcontains: StringnotContains: Stringpattern: Stringformat: StringdiffersFrom: Stringmin: Floatmax: FloatexclusiveMin: FloatexclusiveMax: FloatnotEqual: Float
) onARGUMENT_DEFINITION

API

Available constraints

See stringValidators, numericValidators and formatValidator mapping in src/validators.js.

Available formats

We use some functions from the validator package. See format2fun mapping in src/validators.js.

Customization

Default behavoir

The following code shows how the constraint directive is configured with default behaviour:

// this code:import{constraint}from'node-graphql-constraint-lambda'// is equivalent to:import{prepareConstraintDirective,defaultValidationCallback,defaultErrorMessageCallback}from'node-graphql-constraint-lambda'constconstraint=prepareConstraintDirective(defaultValidationCallback,defaultErrorMessageCallback)

Custom error messages

Error messages are generated using a callback function that by default shows a generic error message. It is possible to change this behavior by implementing a custom callback similar to this one:

constmyErrorMessageCallback=({ argName, cName, cVal, data })=>`Error at field ${argName} in constraint ${cName}:${cVal}, data=${data}`

You might also want to customize certain messages and to keep the default callback as a fallback for all other messages:

constmyErrorMessageCallback=input=>{const{ argName, cName, cVal, data }=inputif(/* decide whether to show custom message */)return"custom error message"// based on inputelsereturndefaultErrorMessageCallback(input)}constconstraint=prepareConstraintDirective(defaultValidationCallback,myErrorMessageCallback)

Custom validation functions

Also the validation functions are implemented through a callback function. The constraint directive comes with a set of useful defaults but if you want to add your own validator, it can be done as follows:

import{createValidationCallback,prepareConstraintDirective,defaultValidators}from'node-graphql-constraint-lambda'// you can merge default validators with your own validatorconstmyValidators={
...defaultValidators,// your custom validator comes hereconstraintName: constrintValue=>dataToValidate=>true/false// Example: numerical pin codes of certain size `@constraint(pin:4)`pin: size=>code=>length(code)===size&&match(/[0-9]+/)(code)}constmyValidationCallback=createValidationCallback(myValidators)// now you can create the constraint classconstconstraint=prepareConstraintDirective(myValidationCallback,defaultErrorMessageCallback)

There is a special format validator that supports the following:

  • @constraint(format: "email")
  • @constraint(format: "base64")
  • @constraint(format: "date")
  • @constraint(format: "ipv4")
  • @constraint(format: "ipv6")
  • @constraint(format: "url")
  • @constraint(format: "uuid")
  • @constraint(format: "futuredate")
  • @constraint(format: "pastdate")
  • @constraint(format: "creditcard")

Let's say we want to extend it to support format: "uppercase" format that checks whether all characters are just uppercase letters:

import{formatValidator,numericValidators,format2fun,stringValidators}from'node-graphql-constraint-lambda'constcustomFormat2Fun={
...format2fun,uppercase: x=>match(/[A-Z]*/)(x)// we could have omitted the `x` parameter due to currying in the// `match` function from ramda}constvalidators={
...formatValidator(customFormat2Fun),
...numericValidators,
...stringValidators}// now you can create the constraint classconstconstraint=prepareConstraintDirective(createValidationCallback(validators),defaultErrorMessageCallback)

About

GraphQL 'constraint' directive written in functional programming style

Topics

Resources

Stars

11 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages