Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mercurius-validation

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mercurius-validation - npm Package Compare versions

Comparing version 1.0.0 to 1.0.1

docs/registration.md

58

docs/api/options.md
# mercurius-validation
- [Plugin options](#plugin-options)
- [Registration](#registration)
## Plugin options
<!-- TODO -->
**mercurius-validation** supports the following options:

@@ -126,57 +124,1 @@

The [JTD](https://jsontypedef.com/docs/) schema definition for the input object type, type field or field argument.
## Registration
The plugin must be registered **after** Mercurius is registered.
```js
'use strict'
const Fastify = require('fastify')
const mercurius = require('mercurius')
const mercuriusValidation = require('mercurius-validation')
const app = Fastify()
const schema = `
directive @validation(
requires: Role = ADMIN,
) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
REVIEWER
USER
UNKNOWN
}
type Query {
add(x: Int, y: Int): Int @validation(requires: USER)
}
`
const resolvers = {
Query: {
add: async (_, { x, y }) => x + y
}
}
app.register(mercurius, {
schema,
resolvers
})
app.register(mercuriusValidation, {
validationContext (context) {
return {
identity: context.reply.request.headers['x-user']
}
},
async applyPolicy (validationDirectiveAST, parent, args, context, info) {
return context.validation.identity === 'admin'
},
validationDirective: 'validation'
})
app.listen(3000)
```
# Directive validation
- [Using the GraphQL definitions within your schema](#using-the-graphql-definitions-within-your-schema)
- [GraphQL argument validation](#graphql-argument-validation)
- [GraphQL Input Object type field validation](#graphql-input-object-type-field-validation)
- [GraphQL Input Object type validation](#graphql-input-object-type-validation)
- [Additional AJV options](#additional-ajv-options)
- [Turning off directive validation](#turning-off-directive-validation)
- [Unsupported JSON Schema keywords](#unsupported-json-schema-keywords)
By default, Mercurius validation supports `@constraint` Directives out of the box. It is defined as follows:

@@ -49,2 +57,47 @@

## Using the GraphQL definitions within your schema
`mercurius-validation` provides `GraphQLDirective` and type definitions to allow one to use the `@constraint` directive within a GraphQL schema.
For string-based schema definitions, you can use as follows:
```js
'use strict'
const mercuriusValidation = require('mercurius-validation')
const schema = `
${mercuriusValidation.graphQLTypeDefs}
type Message {
id: ID!
text: String
}
input Filters {
id: ID
text: String @constraint(minLength: 1)
}
type Query {
message(id: ID @constraint(type: "string", minLength: 1)): Message
messages(filters: Filters): [Message]
}
`
```
For executable schema definitions, you can use as follows:
```js
'use strict'
const { parse, GraphQLSchema } = require('graphql')
const mercuriusValidation = require('mercurius-validation')
// Define your executable schema as normal
const graphQLSchemaToExtend = new GraphQLSchema({ ... })
const schema = extendSchema(graphQLSchemaToExtend, parse(mercuriusValidation.graphQLTypeDefs))
```
## GraphQL argument validation

@@ -286,2 +339,13 @@

## Turning off directive validation
If you don't want to run directive validation within the plugin, you can turn it off during plugin registration:
```js
app.register(mercuriusValidation, {
directiveValidation: false
// Additional options here
})
```
## Unsupported JSON Schema keywords

@@ -288,0 +352,0 @@

2

docs/function-validation.md
# Function validation
- [GraphQL argument validation](#graphql-argument-validation)
You can setup Mercurius validation to run custom functions on arguments when defining in-band validation schemas. It supports the following validation definitions:

@@ -4,0 +6,0 @@

# JSON Schema validation
- [GraphQL argument validation](#graphql-argument-validation)
- [GraphQL Input Object type field validation](#graphql-input-object-type-field-validation)
- [GraphQL Input Object type validation](#graphql-input-object-type-validation)
- [Additional AJV options](#additional-ajv-options)
- [Custom errors](#custom-errors)
- [Type inference](#type-inference)
- [Caveats](#caveats)
By default, Mercurius validation runs in JSON Schema mode when defining in-band validation schemas. It supports the following validation definitions:

@@ -4,0 +12,0 @@

# JTD validation
- [GraphQL argument validation](#graphql-argument-validation)
- [GraphQL Input Object type field validation](#graphql-input-object-type-field-validation)
- [GraphQL Input Object type validation](#graphql-input-object-type-validation)
- [Additional AJV options](#additional-ajv-options)
You can setup Mercurius validation to run in JTD mode when defining in-band validation schemas. It supports the following validation definitions:

@@ -11,3 +16,3 @@

To enable JTD mode, set the following at registration:
To enable JTD mode, set the `mode` options to `"JTD"` at registration:

@@ -14,0 +19,0 @@ ```js

@@ -38,11 +38,11 @@ 'use strict'

function inferJSONSchemaType (type) {
function inferJSONSchemaType (type, isNonNull) {
if (type === GraphQLString) {
return { type: 'string' }
return isNonNull ? { type: 'string' } : { type: ['string', 'null'] }
}
if (type === GraphQLInt) {
return { type: 'integer' }
return isNonNull ? { type: 'integer' } : { type: ['integer', 'null'] }
}
if (type === GraphQLFloat) {
return { type: 'number' }
return isNonNull ? { type: 'number' } : { type: ['number', 'null'] }
}

@@ -53,4 +53,5 @@ return {}

function getTypeInfo (graphQLType) {
const type = isNonNullType(graphQLType.type) ? graphQLType.type.ofType : graphQLType.type
return [type, getNamedType(type)]
const isNonNull = isNonNullType(graphQLType.type)
const type = isNonNull ? graphQLType.type.ofType : graphQLType.type
return [type, getNamedType(type), isNonNull]
}

@@ -57,0 +58,0 @@

@@ -13,5 +13,5 @@ 'use strict'

class JSONSchemaValidator extends Validator {
[kValidationSchema] (type, namedType, typeValidation, id) {
[kValidationSchema] (type, namedType, isNonNull, typeValidation, id) {
let builtValidationSchema = {
...inferJSONSchemaType(namedType),
...inferJSONSchemaType(namedType, isNonNull),
$id: id

@@ -30,3 +30,3 @@ }

} else if (isListType(type)) {
let items = { ...inferJSONSchemaType(namedType), ...builtValidationSchema.items }
let items = { ...inferJSONSchemaType(namedType, isNonNull), ...builtValidationSchema.items }
if (typeValidation !== null) {

@@ -55,7 +55,7 @@ items = { ...items, ...typeValidation.items }

for (const argument of schemaTypeField.args) {
const [argumentType, namedArgumentType] = getTypeInfo(argument)
const [argumentType, namedArgumentType, isNonNull] = getTypeInfo(argument)
const argumentValidation = fieldValidation !== null ? fieldValidation[argument.name] || null : null
const id = `https://mercurius.dev/validation/${typeName}/${fieldName}/${argument.name}`
const argumentValidationSchema = this[kValidationSchema](argumentType, namedArgumentType, argumentValidation, id)
const argumentValidationSchema = this[kValidationSchema](argumentType, namedArgumentType, isNonNull, argumentValidation, id)

@@ -70,6 +70,6 @@ fieldArgumentsValidationSchema.properties[argument.name] = argumentValidationSchema

[kBuildInputTypeFieldSchema] (typeName, fieldName, schemaTypeField, fieldValidation) {
const [fieldType, namedFieldType] = getTypeInfo(schemaTypeField)
const [fieldType, namedFieldType, isNonNull] = getTypeInfo(schemaTypeField)
const id = `https://mercurius.dev/validation/${typeName}/${fieldName}`
const builtFieldValidationSchema = this[kValidationSchema](fieldType, namedFieldType, fieldValidation, id)
const builtFieldValidationSchema = this[kValidationSchema](fieldType, namedFieldType, isNonNull, fieldValidation, id)

@@ -83,3 +83,3 @@ // Only consider fields where we have inferred the type to avoid any AJV errors

if (typeof builtFieldValidationSchema.type === 'string') {
if (typeof builtFieldValidationSchema.type === 'string' || Array.isArray(builtFieldValidationSchema.type)) {
return builtFieldValidationSchema

@@ -86,0 +86,0 @@ }

{
"name": "mercurius-validation",
"version": "1.0.0",
"version": "1.0.1",
"description": "Mercurius Validation Plugin adds configurable Validation support to Mercurius.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -23,5 +23,8 @@ # mercurius-validation

- [Quick Start](#quick-start)
- [Validation with JSON SChema definitions](#validation-with-json-schema-definitions)
- [Validation with the GraphQL `@constraint` directive](#validation-with-the-graphql-constraint-directive)
- [Examples](#examples)
- [Benchmarks](#benchmarks)
- [API](docs/api/options.md)
- [Registration](docs/registration.md)
- [JSON Schema Validation](docs/json-schema-validation.md)

@@ -40,2 +43,6 @@ - [JTD Validation](docs/jtd-validation.md)

### Validation with JSON Schema definitions
You can setup `mercurius-validation` using a JSON Schema validation definition as follows:
```js

@@ -118,2 +125,72 @@ 'use strict'

### Validation with the GraphQL `@constraint` directive
You can setup `mercurius-validation` with the `@constraint` GraphQL directive. `mercurius-validation` provides the type definitions to include this directive definition within your GraphQL schema.
```js
'use strict'
const Fastify = require('fastify')
const mercurius = require('mercurius')
const mercuriusValidation = require('mercurius-validation')
const schema = `
${mercuriusValidation.graphQLTypeDefs}
type Message {
id: ID!
text: String
}
input Filters {
id: ID
text: String @constraint(minLength: 1)
}
type Query {
message(id: ID @constraint(type: "string", minLength: 1)): Message
messages(filters: Filters): [Message]
}
`
const messages = [
{
id: 0,
text: 'Some system message.'
},
{
id: 1,
text: 'Hello there'
},
{
id: 2,
text: 'Give me a place to stand, a lever long enough and a fulcrum. And I can move the Earth.'
},
{
id: 3,
text: ''
}
]
const resolvers = {
Query: {
message: async (_, { id }) => {
return messages.find(message => message.id === Number(id))
},
messages: async () => {
return messages
}
}
}
const app = Fastify()
app.register(mercurius, {
schema,
resolvers
})
app.register(mercuriusValidation)
app.listen(3000)
```
## Benchmarks

@@ -120,0 +197,0 @@

@@ -170,3 +170,3 @@ 'use strict'

minLength: 1,
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text'

@@ -190,3 +190,3 @@ },

items: {
type: 'string'
type: ['string', 'null']
}

@@ -228,3 +228,3 @@ },

items: {
type: 'string'
type: ['string', 'null']
}

@@ -558,3 +558,3 @@ },

items: {
type: 'string'
type: ['string', 'null']
}

@@ -561,0 +561,0 @@ },

@@ -102,2 +102,3 @@ 'use strict'

topPosts(count: Int!): [Post]
topPostsFloat(count: Float!): [Post]
}`

@@ -120,2 +121,5 @@

return Object.values(posts).filter(p => p.authorId === user.id).slice(0, count)
},
topPostsFloat: (user, { count }, context, info) => {
return Object.values(posts).filter(p => p.authorId === user.id).slice(0, count)
}

@@ -153,2 +157,5 @@ },

count: { type: 'integer', minimum: 1 }
},
topPostsFloat: {
count: { type: 'number', minimum: 1 }
}

@@ -181,2 +188,8 @@ }

}
topPostsFloat(count: 2) {
pid
author {
id
}
}
}

@@ -214,2 +227,16 @@ topPosts(count: 2) {

}
],
topPostsFloat: [
{
pid: 'p1',
author: {
id: 'u1'
}
},
{
pid: 'p3',
author: {
id: 'u1'
}
}
]

@@ -299,3 +326,3 @@ },

$id: 'https://mercurius.dev/validation/Query/me/id',
type: 'integer',
type: ['integer', 'null'],
minimum: 1

@@ -335,3 +362,3 @@ },

$id: 'https://mercurius.dev/validation/Query/topPosts/count',
type: 'integer',
type: ['integer', 'null'],
minimum: 1

@@ -338,0 +365,0 @@ },

@@ -72,3 +72,3 @@ 'use strict'

t.test('JSON Schema validators', t => {
t.plan(17)
t.plan(18)

@@ -280,3 +280,3 @@ t.test('should protect the schema and not affect operations when everything is okay', async (t) => {

$id: 'https://mercurius.dev/validation/Filters/text',
type: 'string',
type: ['string', 'null'],
minLength: 1

@@ -354,3 +354,3 @@ },

$id: 'https://mercurius.dev/validation/Filters/text',
type: 'string',
type: ['string', 'null'],
minLength: 1

@@ -576,3 +576,3 @@ },

$id: 'https://mercurius.dev/validation/Filters/text',
type: 'string',
type: ['string', 'null'],
minLength: 1

@@ -965,3 +965,3 @@ },

text: {
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text'

@@ -1051,3 +1051,3 @@ }

minLength: 1,
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text'

@@ -1072,3 +1072,3 @@ }

minLength: 1,
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text'

@@ -1275,3 +1275,3 @@ },

parentSchema: {
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Query/message/id',

@@ -1310,3 +1310,3 @@ minLength: 1

parentSchema: {
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text',

@@ -1327,3 +1327,3 @@ minLength: 1

parentSchema: {
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text',

@@ -1344,3 +1344,3 @@ minLength: 1

parentSchema: {
type: 'string',
type: ['string', 'null'],
minLength: 1

@@ -1387,3 +1387,3 @@ },

parentSchema: {
type: 'string',
type: ['string', 'null'],
$id: 'https://mercurius.dev/validation/Filters/text',

@@ -1516,3 +1516,3 @@ minLength: 1

parentSchema: {
type: 'integer',
type: ['integer', 'null'],
$id: 'https://mercurius.dev/validation/Query/message/id',

@@ -1552,3 +1552,3 @@ minimum: 1

parentSchema: {
type: 'integer',
type: ['integer', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -1570,3 +1570,3 @@ minimum: 1

parentSchema: {
type: 'integer',
type: ['integer', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -1588,3 +1588,3 @@ minimum: 1

parentSchema: {
type: 'integer',
type: ['integer', 'null'],
minimum: 1

@@ -1632,3 +1632,3 @@ },

parentSchema: {
type: 'integer',
type: ['integer', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -1761,3 +1761,3 @@ minimum: 1

parentSchema: {
type: 'number',
type: ['number', 'null'],
$id: 'https://mercurius.dev/validation/Query/message/id',

@@ -1797,3 +1797,3 @@ minimum: 1

parentSchema: {
type: 'number',
type: ['number', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -1815,3 +1815,3 @@ minimum: 1

parentSchema: {
type: 'number',
type: ['number', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -1833,3 +1833,3 @@ minimum: 1

parentSchema: {
type: 'number',
type: ['number', 'null'],
minimum: 1

@@ -1877,3 +1877,3 @@ },

parentSchema: {
type: 'number',
type: ['number', 'null'],
$id: 'https://mercurius.dev/validation/Filters/value',

@@ -2076,2 +2076,40 @@ minimum: 1

})
t.test('should support nullable input type arguments', async (t) => {
t.plan(1)
const app = Fastify()
t.teardown(app.close.bind(app))
app.register(mercurius, {
schema: `type Query {
nullableInput(input: String): String
}`,
resolvers: {
Query: {
nullableInput: async (_, { input }) => {
return input
}
}
}
})
app.register(mercuriusValidation)
const query = `query {
nullableInput(input: null)
}`
const response = await app.inject({
method: 'POST',
headers: { 'content-type': 'application/json' },
url: '/graphql',
body: JSON.stringify({ query })
})
t.same(response.json(), {
data: {
nullableInput: null
}
})
})
})

@@ -279,3 +279,3 @@ 'use strict'

$id: 'https://mercurius.dev/validation/Filters/text',
type: 'string',
type: ['string', 'null'],
minLength: 1

@@ -282,0 +282,0 @@ },

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

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc