GraphQL constraint directive written in functional programming style. This directive provides declarative validation of GraphQL arguments.
yarn add node-graphql-constraint-lambda
# or
npm install node-graphql-constraint-lambdaExample 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 serverYou 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_DEFINITIONSee stringValidators, numericValidators and formatValidator mapping in src/validators.js.
We use some functions from the validator package.
See format2fun mapping in src/validators.js.
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)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)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)