Skip to content

Commit

Permalink
Merge pull request #8 from mercurius-js/feature/improve-docs
Browse files Browse the repository at this point in the history
Improve docs and add constraint example to README
  • Loading branch information
jonnydgreen authored Sep 28, 2021
2 parents 442aed9 + 53491f0 commit f396bc3
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 59 deletions.
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ Features:

- [Install](#install)
- [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)
- [JTD Validation](docs/jtd-validation.md)
- [Function Validation](docs/function-validation.md)
Expand All @@ -36,6 +39,10 @@ npm i fastify mercurius mercurius-validation

## Quick Start

### Validation with JSON Schema definitions

You can setup `mercurius-validation` using a JSON Schema validation definition as follows:

```js
'use strict'

Expand Down Expand Up @@ -113,6 +120,76 @@ app.register(mercuriusValidation, {
app.listen(3000)
```

### 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

### Normal GraphQL Server Mode | Without Validation
Expand Down
58 changes: 0 additions & 58 deletions docs/api/options.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# mercurius-validation

- [Plugin options](#plugin-options)
- [Registration](#registration)

## Plugin options

<!-- TODO -->
**mercurius-validation** supports the following options:

Extends: [`AJVOptions`](https://ajv.js.org/options.html)
Expand Down Expand Up @@ -123,59 +121,3 @@ The [JSON Schema](https://json-schema.org/understanding-json-schema/) schema def
### Parameter: `JTD`

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)
```
64 changes: 64 additions & 0 deletions docs/directive-validation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 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:

```gql
Expand Down Expand Up @@ -46,6 +54,51 @@ To get up and running, you can even register the plugin without options (it also
app.register(mercuriusValidation)
```

## 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

If we wanted to make sure the `id` argument had a minimum length of 1, we would define as follows:
Expand Down Expand Up @@ -282,6 +335,17 @@ When run, this would produce the following validation error when an input is not
}
```

## 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

If we do not yet support a JSON Schema keyword, you can use the `schema` argument as a workaround.
Expand Down
2 changes: 2 additions & 0 deletions docs/function-validation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# 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:

- Validation on GraphQL field arguments
Expand Down
8 changes: 8 additions & 0 deletions docs/json-schema-validation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 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:

- Validation on GraphQL field arguments
Expand Down
7 changes: 6 additions & 1 deletion docs/jtd-validation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# 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:

- Validation on GraphQL field arguments
Expand All @@ -8,7 +13,7 @@ You can setup Mercurius validation to run in JTD mode when defining in-band vali

When defining validations for each of the above, any valid JTD keyword is supported.

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

```js
app.register(mercuriusValidation, {
Expand Down
56 changes: 56 additions & 0 deletions docs/registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Registration

The `mercurius-validation` 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
})

// After initial setup, register Mercurius validation
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)
```

0 comments on commit f396bc3

Please sign in to comment.