Gathering detailed insights and metrics for graphql-constraint-directive
Gathering detailed insights and metrics for graphql-constraint-directive
Gathering detailed insights and metrics for graphql-constraint-directive
Gathering detailed insights and metrics for graphql-constraint-directive
@treorisoft/graphql-validator-directive
Allows creating custom constraint directives to validate queries and inputs. Inspired by [graphql-constraint-directive](https://github.com/confuser/graphql-constraint-directive).
node-graphql-constraint-lambda
GraphQL 'constraint' directive written in functional programming style
@aws-sdk/middleware-location-constraint
[![NPM version](https://img.shields.io/npm/v/@aws-sdk/middleware-location-constraint/latest.svg)](https://www.npmjs.com/package/@aws-sdk/middleware-location-constraint) [![NPM downloads](https://img.shields.io/npm/dm/@aws-sdk/middleware-location-constrain
@aws-amplify/graphql-directives
Directive definitions for Amplify GraphQL transformers.
npm install graphql-constraint-directive
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
569 Stars
182 Commits
74 Forks
6 Watching
10 Branches
35 Contributors
Updated on 26 Nov 2024
Minified
Minified + Gzipped
JavaScript (99.89%)
TypeScript (0.11%)
Cumulative downloads
Total Downloads
Last day
-2.1%
7,538
Compared to previous day
Last week
5.2%
35,788
Compared to previous week
Last month
12.9%
139,944
Compared to previous month
Last year
-7.4%
1,523,519
Compared to previous year
3
1
Allows using @constraint as a directive to validate input data. Inspired by Constraints Directives RFC and OpenAPI
npm install graphql-constraint-directive
For GraphQL v15 and below, use v2 of this package
npm install graphql-constraint-directive@v2
There are multiple ways to make use of the constraint directive in your project. Below outlines the benefits and caveats. Please choose the most appropriate to your use case.
Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
graphql
library, works everywhere1const { constraintDirective, constraintDirectiveTypeDefs } = require('graphql-constraint-directive') 2const express = require('express') 3const { ApolloServer } = require('apollo-server-express') 4const { makeExecutableSchema } = require('@graphql-tools/schema') 5const typeDefs = ` 6 type Query { 7 books: [Book] 8 } 9 type Book { 10 title: String 11 } 12 type Mutation { 13 createBook(input: BookInput): Book 14 } 15 input BookInput { 16 title: String! @constraint(minLength: 5, format: "email") 17 }` 18 19let schema = makeExecutableSchema({ 20 typeDefs: [constraintDirectiveTypeDefs, typeDefs], 21}) 22schema = constraintDirective()(schema) 23 24const app = express() 25const server = new ApolloServer({ schema }) 26 27await server.start() 28 29server.applyMiddleware({ app }) 30
Implementation based on server plugin. Common server plugins are implemented,
function validateQuery(schema, query, variables, operationName)
can be used to implement additional plugins.
Use as an Envelop plugin in supported frameworks, e.g. GraphQL Yoga.
Functionality is plugged in execute
phase
This plugin requires the following dependencies installed in your project:
@envelop/core
- ^2.0.0
1const { createEnvelopQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive') 2const express = require('express') 3const { createServer } = require('@graphql-yoga/node') 4const { makeExecutableSchema } = require('@graphql-tools/schema') 5 6const typeDefs = ` 7 type Query { 8 books: [Book] 9 } 10 type Book { 11 title: String 12 } 13 type Mutation { 14 createBook(input: BookInput): Book 15 } 16 input BookInput { 17 title: String! @constraint(minLength: 5, format: "email") 18 }` 19 20let schema = makeExecutableSchema({ 21 typeDefs: [constraintDirectiveTypeDefs, typeDefs], 22}) 23 24const app = express() 25 26const yoga = createServer({ 27 schema, 28 plugins: [createEnvelopQueryValidationPlugin()], 29 graphiql: false 30}) 31 32app.use('/', yoga) 33 34app.listen(4000);
As an Apollo 3 Server plugin
This plugin requires the following dependencies installed in your project:
1const { createApolloQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive') 2const express = require('express') 3const { ApolloServer } = require('apollo-server-express') 4const { makeExecutableSchema } = require('@graphql-tools/schema') 5 6const typeDefs = ` 7 type Query { 8 books: [Book] 9 } 10 type Book { 11 title: String 12 } 13 type Mutation { 14 createBook(input: BookInput): Book 15 } 16 input BookInput { 17 title: String! @constraint(minLength: 5, format: "email") 18 }` 19 20let schema = makeExecutableSchema({ 21 typeDefs: [constraintDirectiveTypeDefs, typeDefs], 22}) 23 24const plugins = [ 25 createApolloQueryValidationPlugin({ 26 schema 27 }) 28] 29 30const app = express() 31const server = new ApolloServer({ 32 schema, 33 plugins 34}) 35 36await server.start() 37 38server.applyMiddleware({ app })
As an Apollo 4 Server plugin
This plugin requires the following dependencies installed in your project:
@apollo/server
- ^4.0.0
graphql-tag
- ^2.0.0
1const { createApollo4QueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive/apollo4') 2const { ApolloServer } = require('@apollo/server') 3const { startStandaloneServer } = require('@apollo/server/standalone'); 4const { makeExecutableSchema } = require('@graphql-tools/schema') 5 6const typeDefs = ` 7 type Query { 8 books: [Book] 9 } 10 type Book { 11 title: String 12 } 13 type Mutation { 14 createBook(input: BookInput): Book 15 } 16 input BookInput { 17 title: String! @constraint(minLength: 5, format: "email") 18 }` 19 20let schema = makeExecutableSchema({ 21 typeDefs: [constraintDirectiveTypeDefs, typeDefs], 22}) 23 24const plugins = [ 25 createApollo4QueryValidationPlugin() 26] 27 28const server = new ApolloServer({ 29 schema, 30 plugins 31}) 32 33await startStandaloneServer(server);
There is a small change required to make the Apollo Server quickstart work when trying to build an Apollo Subgraph Server.
We must use the buildSubgraphSchema
function to build a schema that can be passed to an Apollo Gateway/supergraph, instead of makeExecuteableSchema
. This uses makeExecutableSchema
under the hood.
This plugin requires the following dependencies installed in your project:
@apollo/server
- ^4.0.0
graphql-tag
- ^2.0.0
1import { ApolloServer } from '@apollo/server'; 2import { startStandaloneServer } from '@apollo/server/standalone'; 3import { buildSubgraphSchema } from '@apollo/subgraph'; 4import { createApollo4QueryValidationPlugin, constraintDirectiveTypeDefsGql } from 'graphql-constraint-directive/apollo4'; 5 6const typeDefs = gql` 7 extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@shareable"]) 8 9 type Query { 10 books: [Book] 11 } 12 type Book { 13 title: String 14 } 15 type Mutation { 16 createBook(input: BookInput): Book 17 } 18 input BookInput { 19 title: String! @constraint(minLength: 5, format: "email") 20 } 21`; 22 23const schema = buildSubgraphSchema({ 24 typeDefs: [constraintDirectiveTypeDefsGql, typeDefs] 25}); 26 27const plugins = [ 28 createApollo4QueryValidationPlugin() 29] 30 31const server = new ApolloServer({ 32 schema, 33 plugins 34}); 35 36await startStandaloneServer(server);
This implementation is untested now, as express-graphql
module is not maintained anymore.
As a Validation rule when query variables
are available
1const { createQueryValidationRule, constraintDirectiveTypeDefs } = require('graphql-constraint-directive') 2const express = require('express') 3const { graphqlHTTP } = require('express-graphql') 4const { makeExecutableSchema } = require('@graphql-tools/schema') 5 6const typeDefs = ` 7 type Query { 8 books: [Book] 9 } 10 type Book { 11 title: String 12 } 13 type Mutation { 14 createBook(input: BookInput): Book 15 } 16 input BookInput { 17 title: String! @constraint(minLength: 5, format: "email") 18 }` 19 20let schema = makeExecutableSchema({ 21 typeDefs: [constraintDirectiveTypeDefs, typeDefs], 22}) 23 24const app = express() 25 26app.use( 27 '/api', 28 graphqlHTTP(async (request, response, { variables }) => ({ 29 schema, 30 validationRules: [ 31 createQueryValidationRule({ 32 variables 33 }) 34 ] 35 })) 36) 37app.listen(4000); 38
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
1const { constraintDirectiveTypeDefs, constraintDirectiveDocumentation } = require('graphql-constraint-directive') 2const { makeExecutableSchema } = require('@graphql-tools/schema') 3 4const typeDefs = ... 5 6let schema = makeExecutableSchema({ 7 typeDefs: [constraintDirectiveTypeDefs, typeDefs] 8}) 9 10schema = constraintDirectiveDocumentation()(schema); 11 12// 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:
1""" 2Existing field or argument description. 3""" 4fieldOrArgument: String @constraint(minLength: 10, maxLength: 50)
Transformed schema:
1""" 2Existing field or argument description. 3 4*Constraints:* 5* Minimum length: `10` 6* Maximum length: `50` 7""" 8fieldOrArgument: String @constraint(minLength: 10, maxLength: 50)
CommonMark 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.
1schema = constraintDirectiveDocumentation(
2 {
3 header: '*Changed header:*',
4 descriptionsMap: {
5 minLength: 'Changed Minimum length',
6 maxLength: 'Changed Maximum length',
7 startsWith: 'Changed Starts with',
8 endsWith: 'Changed Ends with',
9 contains: 'Changed Contains',
10 notContains: 'Changed Doesn\'t contain',
11 pattern: 'Changed Must match RegEx pattern',
12 format: 'Changed Must match format',
13 min: 'Changed Minimum value',
14 max: 'Changed Maximum value',
15 exclusiveMin: 'Changed Grater than',
16 exclusiveMax: 'Changed Less than',
17 multipleOf: 'Changed Must be a multiple of',
18 minItems: 'Changed Minimum number of items',
19 maxItems: 'Changed Maximum number of items'
20 }
21 }
22)(schema);
@constraint(minLength: 5)
Restrict to a minimum length
@constraint(maxLength: 5)
Restrict to a maximum length
@constraint(startsWith: "foo")
Ensure value starts with foo
@constraint(endsWith: "foo")
Ensure value ends with foo
@constraint(contains: "foo")
Ensure value contains foo
@constraint(notContains: "foo")
Ensure value does not contain foo
@constraint(pattern: "^[0-9a-zA-Z]*$")
Ensure value matches regex, e.g. alphanumeric
@constraint(format: "email")
Ensure value is in a particular format
Supported formats:
You can add your own custom formats by passing a formats
object to the plugin options. See example below.
@constraint(format: "my-custom-format")
1const formats = {
2 'my-custom-format': (value) => {
3 if (value === 'foo') {
4 return true
5 }
6
7 throw new GraphQLError('Value must be foo')
8 }
9};
10
11// Envelop
12createEnvelopQueryValidationPlugin({ formats })
13
14// Apollo 3 Server
15createApolloQueryValidationPlugin({ formats })
16
17// Apollo 4 Server
18createApollo4QueryValidationPlugin({ formats })
@constraint(min: 3)
Ensure value is greater than or equal to
@constraint(max: 3)
Ensure value is less than or equal to
@constraint(exclusiveMin: 3)
Ensure value is greater than
@constraint(exclusiveMax: 3)
Ensure value is less than
@constraint(multipleOf: 10)
Ensure value is a multiple
@constraint(minItems: 3)
Restrict array/List to a minimum length
@constraint(maxItems: 3)
Restrict array/List to a maximum length
Each validation error throws a ConstraintDirectiveError
. Combined with a formatError function, this can be used to customise error messages.
1{ 2 code: 'ERR_GRAPHQL_CONSTRAINT_VALIDATION', 3 fieldName: 'theFieldName', 4 context: [ { arg: 'argument name which failed', value: 'value of argument' } ] 5}
1const formatError = function (error) { 2 const code = error?.originalError?.originalError?.code || error?.originalError?.code || error?.code 3 if (code === 'ERR_GRAPHQL_CONSTRAINT_VALIDATION') { 4 // return a custom object 5 } 6 7 return error 8} 9 10app.use('/graphql', bodyParser.json(), graphqlExpress({ schema, formatError })) 11
Throws a UserInputError
for each validation error.
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.
The Envelop plugin throws a prefilled GraphQLError
for each validation error.
@constraint(uniqueTypeName: "Unique_Type_Name")
Override the unique type name generate by the library to the one passed as an argument.
Has meaning only for Schema wrapper
implementation.
No vulnerabilities found.
Reason
20 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
6 existing vulnerabilities detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 3
Details
Reason
Found 3/24 approved changesets -- score normalized to 1
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
Reason
security policy file not detected
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-25
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More