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.0.0 to 5.1.0

test/snapshots/ws-1.txt

19

apollo4.d.ts

@@ -1,6 +0,19 @@

import {GraphQLSchema} from "graphql";
import {DocumentNode, GraphQLSchema} from "graphql";
import {ApolloServerPlugin} from '@apollo/server';
export const constraintDirectiveTypeDefs: string
/**
* Constraint directive typeDef as a `string`
*/
export const constraintDirectiveTypeDefs: string;
export function createApollo4QueryValidationPlugin ( options: { schema: GraphQLSchema } ) : ApolloServerPlugin;
/**
* Constraint directive typeDef as a `DocumentNode`
*/
export const constraintDirectiveTypeDefsGql: DocumentNode;
/**
* Create Apollo 4 validation plugin.
*
* @param options to setup plugin. `schema` is deprecated now, not used, as plugins gets schema from the Apollo Server.
*/
export function createApollo4QueryValidationPlugin ( options: { schema?: GraphQLSchema } ) : ApolloServerPlugin;
const {
separateOperations,
buildSchema,
GraphQLError

@@ -9,4 +10,13 @@ } = require('graphql')

function createApollo4QueryValidationPlugin ({ schema }) {
let currentSchema
function createApollo4QueryValidationPlugin () {
return {
async serverWillStart () {
return {
schemaDidLoadOrUpdate ({ apiSchema, coreSupergraphSdl }) {
if (coreSupergraphSdl) { currentSchema = buildSchema(coreSupergraphSdl) } else { currentSchema = apiSchema }
}
}
},
async requestDidStart () {

@@ -21,3 +31,3 @@ return ({

const errors = validateQuery(
schema,
currentSchema,
query,

@@ -24,0 +34,0 @@ request.variables,

@@ -5,12 +5,66 @@ import {GraphQLSchema, GraphQLError, DocumentNode, ValidationContext} from "graphql";

/**
* Schema transformer which adds custom types performing validations based on the @constraint directives.
*/
export function constraintDirective () : (schema: GraphQLSchema) => GraphQLSchema;
interface DocumentationOptions {
/** Header for the constraints documentation block in the field or argument description */
header?: string;
/** Names for distinct constraint types */
descriptionsMap?: {
minLength: string,
maxLength: string,
startsWith: string,
endsWith: string,
contains: string,
notContains: string,
pattern: string,
format: string,
min: string,
max: string,
exclusiveMin: string,
exclusiveMax: string,
multipleOf: string,
minItems: string,
maxItems: string
};
}
/**
* Schema transformer which adds @constraint directives documentation to the fields and arguments descriptions.
* Documentation not added if it already exists (`header` is present in the field or argument description)
*
* @param options options to customize the documentation process
*/
export function constraintDirectiveDocumentation (options: DocumentationOptions) : (schema: GraphQLSchema) => GraphQLSchema;
/**
* Type definition for @constraint directive.
*/
export const constraintDirectiveTypeDefs: string
/**
* Method for query validation based on the @constraint directives defined in the schema.
*
* @param schema GraphQL schema to look for directives
* @param query GraphQL query to validate
* @param variables used in the query to validate
* @param operationName optional name of the GraphQL operation to validate
*/
export function validateQuery () : (schema: GraphQLSchema, query: DocumentNode, variables: Record<string, any>, operationName?: string) => Array<GraphQLError>;
/**
* Create Apollo 3 plugin performing query validation.
*/
export function createApolloQueryValidationPlugin ( options: { schema: GraphQLSchema } ) : PluginDefinition;
/**
* Create JS GraphQL Validation Rule performing query validation.
*/
export function createQueryValidationRule( options: { [key: string]: any }) : (context: ValidationContext) => QueryValidationVisitor;
/**
* Create Envelop plugin performing query validation.
*/
export function createEnvelopQueryValidationPlugin() : object;

@@ -9,3 +9,4 @@ const {

separateOperations,
GraphQLError
GraphQLError,
getDirectiveValues
} = require('graphql')

@@ -15,3 +16,3 @@ const QueryValidationVisitor = require('./lib/query-validation-visitor.js')

const { getConstraintTypeObject, getScalarType } = require('./lib/type-utils')
const { constraintDirectiveTypeDefs } = require('./lib/type-defs')
const { constraintDirectiveTypeDefs, constraintDirectiveTypeDefsObj } = require('./lib/type-defs')

@@ -100,2 +101,73 @@ function constraintDirective () {

function constraintDirectiveDocumentation (options) {
// Default descriptions, can be changed through options
let DESCRIPTINS_MAP = {
minLength: 'Minimal length',
maxLength: 'Maximal length',
startsWith: 'Starts with',
endsWith: 'Ends with',
contains: 'Contains',
notContains: 'Doesn\'t contain',
pattern: 'Must match RegEx pattern',
format: 'Must match format',
min: 'Minimal value',
max: 'Maximal value',
exclusiveMin: 'Grater than',
exclusiveMax: 'Less than',
multipleOf: 'Must be a multiple of',
minItems: 'Minimal number of items',
maxItems: 'Maximal number of items'
}
if (options?.descriptionsMap) {
DESCRIPTINS_MAP = options.descriptionsMap
}
let HEADER = '*Constraints:*'
if (options?.header) {
HEADER = options.header
}
function documentConstraintDirective (fieldConfig, directiveArgumentMap) {
if (fieldConfig.description) {
// skip documentation if it is already here
if (fieldConfig.description.includes(HEADER)) return
// add two new lines to separate from previous description by paragraph
fieldConfig.description += '\n\n'
} else {
fieldConfig.description = ''
}
fieldConfig.description += HEADER + '\n'
Object.entries(directiveArgumentMap).forEach(([key, value]) => {
if (key === 'uniqueTypeName') return
fieldConfig.description += `* ${DESCRIPTINS_MAP[key] ? DESCRIPTINS_MAP[key] : key}: \`${value}\`\n`
})
}
return (schema) =>
mapSchema(schema, {
[MapperKind.FIELD]: (fieldConfig) => {
const directiveArgumentMap = getDirectiveValues(constraintDirectiveTypeDefsObj, fieldConfig.astNode)
if (directiveArgumentMap) {
documentConstraintDirective(fieldConfig, directiveArgumentMap)
return fieldConfig
}
},
[MapperKind.ARGUMENT]: (fieldConfig) => {
const directiveArgumentMap = getDirectiveValues(constraintDirectiveTypeDefsObj, fieldConfig.astNode)
if (directiveArgumentMap) {
documentConstraintDirective(fieldConfig, directiveArgumentMap)
return fieldConfig
}
}
})
}
function validateQuery (schema, query, variables, operationName) {

@@ -165,2 +237,2 @@ const typeInfo = new TypeInfo(schema)

module.exports = { constraintDirective, constraintDirectiveTypeDefs, validateQuery, createApolloQueryValidationPlugin, createEnvelopQueryValidationPlugin, createQueryValidationRule }
module.exports = { constraintDirective, constraintDirectiveDocumentation, constraintDirectiveTypeDefs, validateQuery, createApolloQueryValidationPlugin, createEnvelopQueryValidationPlugin, createQueryValidationRule }

7

package.json
{
"name": "graphql-constraint-directive",
"version": "5.0.0",
"version": "5.1.0",
"description": "Validate GraphQL fields",

@@ -9,2 +9,3 @@ "main": "index.js",

"test": "standard && nyc --reporter=html --reporter=text --reporter=lcov mocha test/**/testsuite-full.js",
"test-documentation": "standard && nyc --reporter=html --reporter=text --reporter=lcov mocha test/**/testsuite-documentation.js",
"test-schema-wrapper": "standard && nyc --reporter=html --reporter=text --reporter=lcov mocha test/**/testsuite-schema-wrapper.js",

@@ -37,4 +38,4 @@ "test-apollo-plugin": "standard && nyc --reporter=html --reporter=text --reporter=lcov mocha test/**/testsuite-apollo-plugin.js",

"devDependencies": {
"apollo-server-express": "3.11.1",
"@apollo/server": "4.3.2",
"apollo-server-express": "3.12.0",
"@apollo/server": "4.5.0",
"coveralls": "3.1.1",

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

@@ -25,6 +25,6 @@ # graphql-constraint-directive

Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
#### Benefits
* based on `graphql` library, works everywhere
* based on `graphql` library, works everywhere
* posibility to also validate GraphQL response data

@@ -85,2 +85,5 @@

This plugin requires the following dependencies installed in your project:
* `@envelop/core` - `^2.0.0`
```js

@@ -127,2 +130,5 @@ const { createEnvelopQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive')

This plugin requires the following dependencies installed in your project:
* dependencies required for your selected Apollo Server 3 variant
```js

@@ -159,3 +165,3 @@ const { createApolloQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive')

const app = express()
const server = new ApolloServer({
const server = new ApolloServer({
schema,

@@ -174,9 +180,11 @@ plugins

This plugin requires the following dependencies installed in your project:
* `@apollo/server` - `^4.0.0`
* `graphql-tag` - `^2.0.0`
```js
const { createApollo4QueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive/apollo4')
const express = require('express')
const { ApolloServer } = require('@apollo/server')
const { startStandaloneServer } = require('@apollo/server/standalone');
const { makeExecutableSchema } = require('@graphql-tools/schema')
const cors = require('cors')
const { json } = require('body-parser')

@@ -202,9 +210,6 @@ const typeDefs = `

const plugins = [
createApollo4QueryValidationPlugin({
schema
})
createApollo4QueryValidationPlugin()
]
const app = express()
const server = new ApolloServer({
const server = new ApolloServer({
schema,

@@ -214,10 +219,3 @@ plugins

await server.start()
app.use(
'/',
cors(),
json(),
expressMiddleware(server)
)
await startStandaloneServer(server);
```

@@ -229,2 +227,6 @@ #### Apollo 4 Subgraph server

This plugin requires the following dependencies installed in your project:
* `@apollo/server` - `^4.0.0`
* `graphql-tag` - `^2.0.0`
```ts

@@ -258,5 +260,3 @@ import { ApolloServer } from '@apollo/server';

const plugins = [
createApollo4QueryValidationPlugin({
schema
})
createApollo4QueryValidationPlugin()
]

@@ -274,5 +274,5 @@

*This implementation is untested now, as [`express-graphql` module](https://github.com/graphql/express-graphql) is not maintained anymore.*
*This implementation is untested now, as [`express-graphql` module](https://github.com/graphql/express-graphql) is not maintained anymore.*
As a [Validation rule](https://graphql.org/graphql-js/validation/) when query `variables` are available
As a [Validation rule](https://graphql.org/graphql-js/validation/) when query `variables` are available

@@ -319,3 +319,78 @@ ```js

```
### Schema documentation
You can use the provided schema transformation to automatically add `@constraint` documentation into fields and arguments descriptions. By default directives are not typically present in the exposed introspected schema
```js
const { constraintDirectiveTypeDefs, constraintDirectiveDocumentation } = require('graphql-constraint-directive')
const { makeExecutableSchema } = require('@graphql-tools/schema')
const typeDefs = ...
let schema = makeExecutableSchema({
typeDefs: [constraintDirectiveTypeDefs, typeDefs]
})
schema = constraintDirectiveDocumentation()(schema);
// any constraint directive handler implementation
```
This transformation appends `constraint documentation header`, and then a list of `constraint conditions descriptions` to the description of each field and argument where the `@constraint` directive is used.
Original schema:
```graphql
"""
Existing field or argument description.
"""
fieldOrArgument: String @constraint(minLength: 10, maxLength: 50)
```
Transformed schema:
```graphql
"""
Existing field or argument description.
*Constraints:*
* Minimum length: `10`
* Maximum length: `50`
"""
fieldOrArgument: String @constraint(minLength: 10, maxLength: 50)
```
[CommonMark](https://spec.commonmark.org) is used in the desccription for better readability.
If `constraint documentation header` already exists in the field or argument description, then
constraint documentation is not appended. This allows you to override constraint description
when necessary, or use this in a chain of subgraph/supergraph schemes.
Both `constraint documentation header` and `constraint conditions descriptions` can be customized
during the transformation creation, eg. to localize them.
```js
schema = constraintDirectiveDocumentation(
{
header: '*Changed header:*',
descriptionsMap: {
minLength: 'Changed Minimum length',
maxLength: 'Changed Maximum length',
startsWith: 'Changed Starts with',
endsWith: 'Changed Ends with',
contains: 'Changed Contains',
notContains: 'Changed Doesn\'t contain',
pattern: 'Changed Must match RegEx pattern',
format: 'Changed Must match format',
min: 'Changed Minimum value',
max: 'Changed Maximum value',
exclusiveMin: 'Changed Grater than',
exclusiveMax: 'Changed Less than',
multipleOf: 'Changed Must be a multiple of',
minItems: 'Changed Minimum number of items',
maxItems: 'Changed Maximum number of items'
}
}
)(schema);
```
## API

@@ -425,4 +500,4 @@ ### String

#### Apollo Server 4
Throws a prefilled `GraphQLError` with `extensions.code` set to `BAD_USER_INPUT` and http status code `400`.
In case of more validation errors, top level error is generic with `Query is invalid, for details see extensions.validationErrors` message,
Throws a prefilled `GraphQLError` with `extensions.code` set to `BAD_USER_INPUT` and http status code `400`.
In case of more validation errors, top level error is generic with `Query is invalid, for details see extensions.validationErrors` message,
detailed errors are stored in `extensions.validationErrors` of this error.

@@ -435,3 +510,3 @@

```@constraint(uniqueTypeName: "Unique_Type_Name")```
Override the unique type name generate by the library to the one passed as an argument.
Override the unique type name generate by the library to the one passed as an argument.
Has meaning only for `Schema wrapper` implementation.

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

const plugins = [
createApollo4QueryValidationPlugin({
schema
})
createApollo4QueryValidationPlugin()
]

@@ -26,0 +24,0 @@

@@ -6,1 +6,2 @@ require('./testsuite-schema-wrapper')

// require('./testsuite-validation-rule-express-graphql') // deprecated, may be removed later or rewritent to another server if available
require('./testsuite-documentation')
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