Socket
Socket
Sign inDemoInstall

graphql-constraint-directive

Package Overview
Dependencies
8
Maintainers
1
Versions
31
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.1.1 to 5.2.0

5

apollo4.js

@@ -12,3 +12,3 @@ const {

function createApollo4QueryValidationPlugin () {
function createApollo4QueryValidationPlugin (options = {}) {
return {

@@ -34,3 +34,4 @@ async serverWillStart () {

request.variables,
request.operationName
request.operationName,
options
)

@@ -37,0 +38,0 @@

@@ -174,3 +174,3 @@ const {

function validateQuery (schema, query, variables, operationName) {
function validateQuery (schema, query, variables, operationName, pluginOptions = {}) {
const typeInfo = new TypeInfo(schema)

@@ -185,5 +185,7 @@

)
const visitor = new QueryValidationVisitor(context, {
variables,
operationName
operationName,
pluginOptions
})

@@ -196,3 +198,3 @@

function createApolloQueryValidationPlugin ({ schema }) {
function createApolloQueryValidationPlugin ({ schema }, options = {}) {
return {

@@ -210,3 +212,4 @@ async requestDidStart () {

request.variables,
request.operationName
request.operationName,
options
)

@@ -225,6 +228,6 @@ if (errors.length > 0) {

function createEnvelopQueryValidationPlugin () {
function createEnvelopQueryValidationPlugin (options = {}) {
return {
onExecute ({ args, setResultAndStopExecution }) {
const errors = validateQuery(args.schema, args.document, args.variableValues, args.operationName)
const errors = validateQuery(args.schema, args.document, args.variableValues, args.operationName, options)
if (errors.length > 0) {

@@ -231,0 +234,0 @@ setResultAndStopExecution({ errors: errors.map(err => { return new GraphQLError(err.message, err, { code: err.code, field: err.fieldName, context: err.context, exception: err.originalError }) }) })

25

lib/query-validation-visitor.js

@@ -138,3 +138,3 @@ const { getVariableValues } = require('graphql/execution/values.js')

validateInputTypeValue(this.context, inputObjectTypeDef, argName, variableName, value, this.currentField, variableName)
validateInputTypeValue(this.context, inputObjectTypeDef, argName, variableName, value, this.currentField, variableName, this.options)
} else if (isListType(valueTypeDef)) {

@@ -144,7 +144,7 @@ validateArrayTypeValue(this.context, valueTypeDef, argTypeDef, value, this.currentField, argName, variableName, variableName)

// nothing to validate
if (!value) return
if (!value && value !== '' && value !== 0) return
const fieldNameForError = variableName || this.currentField.name.value + '.' + argName
validateScalarTypeValue(this.context, this.currentField, argTypeDef, valueTypeDef, value, variableName, argName, fieldNameForError, '')
validateScalarTypeValue(this.context, this.currentField, argTypeDef, valueTypeDef, value, variableName, argName, fieldNameForError, '', this.options)
}

@@ -154,3 +154,3 @@ }

function validateScalarTypeValue (context, currentQueryField, typeDefWithDirective, valueTypeDef, value, variableName, argName, fieldNameForError, errMessageAt) {
function validateScalarTypeValue (context, currentQueryField, typeDefWithDirective, valueTypeDef, value, variableName, argName, fieldNameForError, errMessageAt, options = {}) {
if (!typeDefWithDirective.astNode) { return }

@@ -165,3 +165,3 @@

try {
getConstraintValidateFn(st)(fieldNameForError, directiveArgumentMap, value)
getConstraintValidateFn(st)(fieldNameForError, directiveArgumentMap, value, options)
} catch (e) {

@@ -182,7 +182,7 @@ let error

function validateInputTypeValue (context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames) {
function validateInputTypeValue (context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames, options = {}) {
if (!inputObjectTypeDef.astNode) { return }
// use new visitor to traverse input object structure
const visitor = new InputObjectValidationVisitor(context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames)
const visitor = new InputObjectValidationVisitor(context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames, options)

@@ -238,7 +238,7 @@ visit(inputObjectTypeDef.astNode, visitor)

if (isInputObjectType(valueTypeDefArray)) {
validateInputTypeValue(context, valueTypeDefArray, argName, variableName, element, currentField, iFieldNameFullIndexed)
validateInputTypeValue(context, valueTypeDefArray, argName, variableName, element, currentField, iFieldNameFullIndexed, this.options)
} else if (hasNonListValidation) {
const atMessage = ` at "${iFieldNameFullIndexed}"`
validateScalarTypeValue(context, currentField, typeDefWithDirective, valueTypeDef, element, variableName, argName, iFieldNameFullIndexed, atMessage)
validateScalarTypeValue(context, currentField, typeDefWithDirective, valueTypeDef, element, variableName, argName, iFieldNameFullIndexed, atMessage, this.options)
}

@@ -250,3 +250,3 @@ })

class InputObjectValidationVisitor {
constructor (context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames) {
constructor (context, inputObjectTypeDef, argName, variableName, value, currentField, parentNames, options = {}) {
this.context = context

@@ -260,2 +260,3 @@ this.argName = argName

this.parentNames = parentNames
this.options = options

@@ -284,3 +285,3 @@ this.InputValueDefinition = {

validateInputTypeValue(this.context, valueTypeDef, this.argName, this.variableName, value, this.currentField, iFieldNameFull)
validateInputTypeValue(this.context, valueTypeDef, this.argName, this.variableName, value, this.currentField, iFieldNameFull, this.options)
} else if (isListType(valueTypeDef)) {

@@ -292,5 +293,5 @@ validateArrayTypeValue(this.context, valueTypeDef, iFieldTypeDef, value, this.currentField, this.argName, this.variableName, iFieldNameFull)

validateScalarTypeValue(this.context, this.currentField, iFieldTypeDef, valueTypeDef, value, this.variableName, this.argName, iFieldNameFull, ` at "${iFieldNameFull}"`)
validateScalarTypeValue(this.context, this.currentField, iFieldTypeDef, valueTypeDef, value, this.variableName, this.argName, iFieldNameFull, ` at "${iFieldNameFull}"`, this.options)
}
}
}
{
"name": "graphql-constraint-directive",
"version": "5.1.1",
"version": "5.2.0",
"description": "Validate GraphQL fields",

@@ -38,3 +38,3 @@ "main": "index.js",

"apollo-server-express": "3.12.0",
"@apollo/server": "4.5.0",
"@apollo/server": "4.7.4",
"coveralls": "3.1.1",

@@ -41,0 +41,0 @@ "express": "4.18.2",

@@ -429,2 +429,28 @@ # graphql-constraint-directive

#### Custom Format
You can add your own custom formats by passing a `formats` object to the plugin options. See example below.
```@constraint(format: "my-custom-format")```
```js
const formats = {
'my-custom-format': (value) => {
if (value === 'foo') {
return true
}
throw new GraphQLError('Value must be foo')
}
};
// Envelop
createEnvelopQueryValidationPlugin({ formats })
// Apollo 3 Server
createApolloQueryValidationPlugin({ formats })
// Apollo 4 Server
createApollo4QueryValidationPlugin({ formats })
```
### Int/Float

@@ -431,0 +457,0 @@ #### min

const { GraphQLScalarType } = require('graphql')
const { contains, isLength } = require('validator')
const formats = require('./formats')
const defaultFormats = require('./formats')
const ValidationError = require('../lib/error')
class ConstraintStringType extends GraphQLScalarType {
constructor (fieldName, uniqueTypeName, type, args) {
constructor (fieldName, uniqueTypeName, type, args, options = {}) {
super({

@@ -13,3 +13,3 @@ name: uniqueTypeName,

validate(fieldName, args, value)
validate(fieldName, args, value, options)

@@ -21,3 +21,3 @@ return value

validate(fieldName, args, value)
validate(fieldName, args, value, options)

@@ -29,3 +29,3 @@ return type.parseValue(value)

validate(fieldName, args, value)
validate(fieldName, args, value, options)

@@ -38,3 +38,3 @@ return value

function validate (fieldName, args, value) {
function validate (fieldName, args, value, options = {}) {
if (args.minLength && !isLength(value, { min: args.minLength })) {

@@ -82,2 +82,4 @@ throw new ValidationError(fieldName,

if (args.format) {
const pluginOptions = options.pluginOptions || {}
const formats = { ...defaultFormats, ...(pluginOptions.formats || {}) }
const formatter = formats[args.format]

@@ -84,0 +86,0 @@

@@ -7,3 +7,3 @@ const express = require('express')

module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback }) {
module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback, pluginOptions = {} }) {
let schema = makeExecutableSchema({

@@ -19,5 +19,3 @@ typeDefs: [constraintDirectiveTypeDefs, typeDefs],

const plugins = [
createApolloQueryValidationPlugin({
schema
})
createApolloQueryValidationPlugin({ schema }, pluginOptions)
]

@@ -24,0 +22,0 @@

@@ -10,3 +10,3 @@ const express = require('express')

module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback }) {
module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback, pluginOptions = {} }) {
let schema = makeExecutableSchema({

@@ -22,3 +22,3 @@ typeDefs: [constraintDirectiveTypeDefs, typeDefs],

const plugins = [
createApollo4QueryValidationPlugin()
createApollo4QueryValidationPlugin(pluginOptions)
]

@@ -25,0 +25,0 @@

@@ -7,3 +7,3 @@ const express = require('express')

module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback }) {
module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback, pluginOptions = {} }) {
let schema = makeExecutableSchema({

@@ -21,3 +21,3 @@ typeDefs: [constraintDirectiveTypeDefs, typeDefs],

schema,
plugins: [createEnvelopQueryValidationPlugin()],
plugins: [createEnvelopQueryValidationPlugin(pluginOptions)],
graphiql: false

@@ -24,0 +24,0 @@ })

@@ -7,3 +7,3 @@ const express = require('express')

module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback }) {
module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback, pluginOptions = {} }) {
let schema = makeExecutableSchema({

@@ -10,0 +10,0 @@ typeDefs: [constraintDirectiveTypeDefs, typeDefs],

@@ -7,3 +7,3 @@ const express = require('express')

module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback }) {
module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreatedCallback, pluginOptions = {} }) {
let schema = makeExecutableSchema({

@@ -26,3 +26,4 @@ typeDefs: [constraintDirectiveTypeDefs, typeDefs],

createQueryValidationRule({
variables
variables,
pluginOptions
})

@@ -29,0 +30,0 @@ ]

@@ -5,3 +5,5 @@ const { deepStrictEqual, strictEqual } = require('assert')

module.exports.test = function (setup, implType) {
const queryIntType = valueByImplType(implType, 'size_Int_max_3', 'Int')
const queryIntMaxType = valueByImplType(implType, 'size_Int_max_3', 'Int')
const queryIntMinType = valueByImplType(implType, 'size_Int_min_3', 'Int')
const queryStringMinLengthType = valueByImplType(implType, 'search_String_minLength_3', 'String')

@@ -24,3 +26,3 @@ describe('Variables', function () {

const query = /* GraphQL */`
query ($size: ${queryIntType} = 3) {
query ($size: ${queryIntMaxType} = 3) {
books(size: $size) {

@@ -42,3 +44,3 @@ title

const query = /* GraphQL */`
query ($size: ${queryIntType} = 4) {
query ($size: ${queryIntMaxType} = 4) {
books(size: $size) {

@@ -59,3 +61,101 @@ title

})
describe('variable int falsy', function () {
before(async function () {
this.typeDefs = /* GraphQL */`
type Query {
books (size: Int @constraint(min: 3)): [Book]
}
type Book {
title: String
}
`
this.request = await setup({ typeDefs: this.typeDefs })
})
it('should pass', async function () {
const query = /* GraphQL */`
query ($size: ${queryIntMinType} = 3) {
books(size: $size) {
title
}
}
`
const { body, statusCode } = await this.request
.post('/graphql')
.set('Accept', 'application/json')
.send({ query })
strictEqual(statusCode, 200)
deepStrictEqual(body, { data: { books: null } })
})
it('should fail', async function () {
const query = /* GraphQL */`
query ($size: ${queryIntMinType} = 0) {
books(size: $size) {
title
}
}
`
const { body, statusCode } = await this.request
.post('/graphql')
.set('Accept', 'application/json')
.send({ query })
isStatusCodeError(statusCode, implType)
strictEqual(body.errors[0].message,
valueByImplType(implType, 'Expected value of type "size_Int_min_3", found 0;', 'Variable "$size" got invalid value 0.') + ' Must be at least 3')
})
})
describe('variable string falsy', function () {
before(async function () {
this.typeDefs = /* GraphQL */`
type Query {
books (search: String @constraint(minLength: 3)): [Book]
}
type Book {
title: String
}
`
this.request = await setup({ typeDefs: this.typeDefs })
})
it('should pass', async function () {
const query = /* GraphQL */`
query ($search: ${queryStringMinLengthType} = "test") {
books(search: $search) {
title
}
}
`
const { body, statusCode } = await this.request
.post('/graphql')
.set('Accept', 'application/json')
.send({ query })
strictEqual(statusCode, 200)
deepStrictEqual(body, { data: { books: null } })
})
it('should fail - despite being falsy', async function () {
const query = /* GraphQL */`
query ($search: ${queryStringMinLengthType} = "") {
books(search: $search) {
title
}
}
`
const { body, statusCode } = await this.request
.post('/graphql')
.set('Accept', 'application/json')
.send({ query })
isStatusCodeError(statusCode, implType)
strictEqual(body.errors[0].message,
valueByImplType(implType, 'Expected value of type "search_String_minLength_3", found "";', 'Variable "$search" got invalid value "".') + ' Must be at least 3 characters in length')
})
})
})
}

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc