@@ -18,6 +18,19 @@ npm install graphql-constraint-directive@v2
18
18
```
19
19
20
20
## Usage
21
+ 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.
22
+
23
+ ### Schema wrapper
24
+
25
+ Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
26
+
27
+ #### Benefits
28
+ * based on ` graphql ` library, works everywhere
29
+ * posibility to also validate GraphQL response data
30
+
31
+ #### Caveats
32
+ * modifies GraphQL schema, basic scalars (Int, Float, String) are replaced by custom scalars
33
+
21
34
``` js
22
35
const { constraintDirective , constraintDirectiveTypeDefs } = require (' graphql-constraint-directive' )
23
36
const express = require (' express' )
@@ -51,6 +64,150 @@ server.applyMiddleware({ app })
51
64
52
65
```
53
66
67
+ ### Server plugin
68
+
69
+ Implementation based on server plugin. Common server plugins are implemented,
70
+ function ` validateQuery(schema, query, variables, operationName) ` can be used to implement additional plugins.
71
+
72
+ #### Benefits
73
+ * schema stays unmodified
74
+
75
+ #### Caveats
76
+ * runs only in supported servers
77
+ * validates only GraphQL query, not response data
78
+
79
+ #### Envelop
80
+
81
+ Use as an [ Envelop plugin] ( https://www.envelop.dev ) in supported frameworks, e.g. [ GraphQL Yoga] ( https://www.graphql-yoga.com/ ) .
82
+ Functionality is plugged in ` execute ` phase
83
+
84
+ ``` js
85
+ const { createEnvelopQueryValidationPlugin , constraintDirectiveTypeDefs } = require (' graphql-constraint-directive' )
86
+ const express = require (' express' )
87
+ const { createServer } = require (' @graphql-yoga/node' )
88
+ const { makeExecutableSchema } = require (' @graphql-tools/schema' )
89
+
90
+ const typeDefs = `
91
+ type Query {
92
+ books: [Book]
93
+ }
94
+ type Book {
95
+ title: String
96
+ }
97
+ type Mutation {
98
+ createBook(input: BookInput): Book
99
+ }
100
+ input BookInput {
101
+ title: String! @constraint(minLength: 5, format: "email")
102
+ }`
103
+
104
+ let schema = makeExecutableSchema ({
105
+ typeDefs: [constraintDirectiveTypeDefs, typeDefs],
106
+ })
107
+
108
+ const app = express ()
109
+
110
+ const yoga = createServer ({
111
+ schema,
112
+ plugins: [createEnvelopQueryValidationPlugin ()],
113
+ graphiql: false
114
+ })
115
+
116
+ app .use (' /' , yoga)
117
+
118
+ app .listen (4000 );
119
+ ```
120
+
121
+ #### Apollo Server
122
+
123
+ As an [ Apollo Server] ( https://www.apollographql.com/docs/apollo-server/ ) plugin
124
+
125
+ ``` js
126
+ const { createApolloQueryValidationPlugin , constraintDirectiveTypeDefs } = require (' graphql-constraint-directive' )
127
+ const express = require (' express' )
128
+ const { ApolloServer } = require (' apollo-server-express' )
129
+ const { makeExecutableSchema } = require (' @graphql-tools/schema' )
130
+
131
+ const typeDefs = `
132
+ type Query {
133
+ books: [Book]
134
+ }
135
+ type Book {
136
+ title: String
137
+ }
138
+ type Mutation {
139
+ createBook(input: BookInput): Book
140
+ }
141
+ input BookInput {
142
+ title: String! @constraint(minLength: 5, format: "email")
143
+ }`
144
+
145
+ let schema = makeExecutableSchema ({
146
+ typeDefs: [constraintDirectiveTypeDefs, typeDefs],
147
+ })
148
+
149
+ const plugins = [
150
+ createApolloQueryValidationPlugin ({
151
+ schema
152
+ })
153
+ ]
154
+
155
+ const app = express ()
156
+ const server = new ApolloServer ({
157
+ schema,
158
+ plugins
159
+ })
160
+
161
+ await server .start ()
162
+
163
+ server .applyMiddleware ({ app })
164
+ ```
165
+
166
+ #### Express
167
+
168
+ As a [ Validation rule] ( https://graphql.org/graphql-js/validation/ ) when query ` variables ` are available
169
+
170
+ ``` js
171
+ const { createQueryValidationRule , constraintDirectiveTypeDefs } = require (' graphql-constraint-directive' )
172
+ const express = require (' express' )
173
+ const { graphqlHTTP } = require (' express-graphql' )
174
+ const { makeExecutableSchema } = require (' @graphql-tools/schema' )
175
+
176
+ const typeDefs = `
177
+ type Query {
178
+ books: [Book]
179
+ }
180
+ type Book {
181
+ title: String
182
+ }
183
+ type Mutation {
184
+ createBook(input: BookInput): Book
185
+ }
186
+ input BookInput {
187
+ title: String! @constraint(minLength: 5, format: "email")
188
+ }`
189
+
190
+ let schema = makeExecutableSchema ({
191
+ typeDefs: [constraintDirectiveTypeDefs, typeDefs],
192
+ })
193
+
194
+ const app = express ()
195
+
196
+ app .use (
197
+ ' /api' ,
198
+ graphqlHTTP (async (request , response , { variables }) => ({
199
+ schema,
200
+ validationRules: [
201
+ createQueryValidationRule ({
202
+ variables
203
+ })
204
+ ]
205
+ }))
206
+ )
207
+ app .listen (4000 );
208
+
209
+ ```
210
+
54
211
## API
55
212
### String
56
213
#### minLength
@@ -140,6 +297,14 @@ const formatError = function (error) {
140
297
app .use (' /graphql' , bodyParser .json (), graphqlExpress ({ schema, formatError }))
141
298
142
299
` ` `
300
+
301
+ #### Apollo Server
302
+ Throws a [` UserInputError` ](https://www.apollographql.com/docs/apollo-server/data/errors/#bad_user_input) for each validation error
303
+
304
+ #### Envelop
305
+ The Envelop plugin throws a prefilled ` GraphQLError` for each validation error
306
+
143
307
### uniqueTypeName
144
308
` ` ` @constraint (uniqueTypeName: " Unique_Type_Name" )` ` `
145
- Override the unique type name generate by the library to the one passed as an argument
309
+ Override the unique type name generate by the library to the one passed as an argument.
310
+ Has meaning only for ` Schema wrapper` implementation.
0 commit comments