Skip to content

Commit 5c6fa3b

Browse files
veliasconfuser
andauthored
feat: Apollo 4 plugin schema loading improvement (#157)
--------- Co-authored-by: James Mortemore <[email protected]>
1 parent 5749e70 commit 5c6fa3b

File tree

4 files changed

+52
-33
lines changed

4 files changed

+52
-33
lines changed

README.md

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ There are multiple ways to make use of the constraint directive in your project.
2222

2323
### Schema wrapper
2424

25-
Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
25+
Implementation based on schema wrappers - basic scalars are wrapped as custom scalars with validations.
2626

2727
#### Benefits
28-
* based on `graphql` library, works everywhere
28+
* based on `graphql` library, works everywhere
2929
* posibility to also validate GraphQL response data
3030

3131
#### Caveats
@@ -81,6 +81,9 @@ function `validateQuery(schema, query, variables, operationName)` can be used to
8181
Use as an [Envelop plugin](https://www.envelop.dev) in supported frameworks, e.g. [GraphQL Yoga](https://www.graphql-yoga.com/).
8282
Functionality is plugged in `execute` phase
8383

84+
This plugin requires the following dependencies installed in your project:
85+
* `@envelop/core` - `^2.0.0`
86+
8487
```js
8588
const { createEnvelopQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive')
8689
const express = require('express')
@@ -122,6 +125,9 @@ app.listen(4000);
122125

123126
As an [Apollo 3 Server](https://www.apollographql.com/docs/apollo-server/v3) plugin
124127

128+
This plugin requires the following dependencies installed in your project:
129+
* dependencies required for your selected Apollo Server 3 variant
130+
125131
```js
126132
const { createApolloQueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive')
127133
const express = require('express')
@@ -153,7 +159,7 @@ const plugins = [
153159
]
154160

155161
const app = express()
156-
const server = new ApolloServer({
162+
const server = new ApolloServer({
157163
schema,
158164
plugins
159165
})
@@ -167,13 +173,15 @@ server.applyMiddleware({ app })
167173

168174
As an [Apollo 4 Server](https://www.apollographql.com/docs/apollo-server/v4) plugin
169175

176+
This plugin requires the following dependencies installed in your project:
177+
* `@apollo/server` - `^4.0.0`
178+
* `graphql-tag` - `^2.0.0`
179+
170180
```js
171181
const { createApollo4QueryValidationPlugin, constraintDirectiveTypeDefs } = require('graphql-constraint-directive/apollo4')
172-
const express = require('express')
173182
const { ApolloServer } = require('@apollo/server')
183+
const { startStandaloneServer } = require('@apollo/server/standalone');
174184
const { makeExecutableSchema } = require('@graphql-tools/schema')
175-
const cors = require('cors')
176-
const { json } = require('body-parser')
177185

178186
const typeDefs = `
179187
type Query {
@@ -194,31 +202,25 @@ let schema = makeExecutableSchema({
194202
})
195203

196204
const plugins = [
197-
createApollo4QueryValidationPlugin({
198-
schema
199-
})
205+
createApollo4QueryValidationPlugin()
200206
]
201207

202-
const app = express()
203-
const server = new ApolloServer({
208+
const server = new ApolloServer({
204209
schema,
205210
plugins
206211
})
207212

208-
await server.start()
209-
210-
app.use(
211-
'/',
212-
cors(),
213-
json(),
214-
expressMiddleware(server)
215-
)
213+
await startStandaloneServer(server);
216214
```
217215
#### Apollo 4 Subgraph server
218216

219217
There is a small change required to make the Apollo Server quickstart work when trying to build an [Apollo Subgraph Server](https://www.apollographql.com/docs/federation/building-supergraphs/subgraphs-apollo-server/).
220218
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.
221219

220+
This plugin requires the following dependencies installed in your project:
221+
* `@apollo/server` - `^4.0.0`
222+
* `graphql-tag` - `^2.0.0`
223+
222224
```ts
223225
import { ApolloServer } from '@apollo/server';
224226
import { startStandaloneServer } from '@apollo/server/standalone';
@@ -247,9 +249,7 @@ const schema = buildSubgraphSchema({
247249
});
248250

249251
const plugins = [
250-
createApollo4QueryValidationPlugin({
251-
schema
252-
})
252+
createApollo4QueryValidationPlugin()
253253
]
254254

255255
const server = new ApolloServer({
@@ -262,9 +262,9 @@ await startStandaloneServer(server);
262262

263263
#### Express
264264

265-
*This implementation is untested now, as [`express-graphql` module](https://github.com/graphql/express-graphql) is not maintained anymore.*
265+
*This implementation is untested now, as [`express-graphql` module](https://github.com/graphql/express-graphql) is not maintained anymore.*
266266

267-
As a [Validation rule](https://graphql.org/graphql-js/validation/) when query `variables` are available
267+
As a [Validation rule](https://graphql.org/graphql-js/validation/) when query `variables` are available
268268

269269
```js
270270
const { createQueryValidationRule, constraintDirectiveTypeDefs } = require('graphql-constraint-directive')
@@ -411,14 +411,14 @@ app.use('/graphql', bodyParser.json(), graphqlExpress({ schema, formatError }))
411411
Throws a [`UserInputError`](https://www.apollographql.com/docs/apollo-server/data/errors/#bad_user_input) for each validation error.
412412
413413
#### Apollo Server 4
414-
Throws a prefilled `GraphQLError` with `extensions.code` set to `BAD_USER_INPUT` and http status code `400`.
415-
In case of more validation errors, top level error is generic with `Query is invalid, for details see extensions.validationErrors` message,
414+
Throws a prefilled `GraphQLError` with `extensions.code` set to `BAD_USER_INPUT` and http status code `400`.
415+
In case of more validation errors, top level error is generic with `Query is invalid, for details see extensions.validationErrors` message,
416416
detailed errors are stored in `extensions.validationErrors` of this error.
417417
418418
#### Envelop
419419
The Envelop plugin throws a prefilled `GraphQLError` for each validation error.
420420
421421
### uniqueTypeName
422422
```@constraint(uniqueTypeName: "Unique_Type_Name")```
423-
Override the unique type name generate by the library to the one passed as an argument.
423+
Override the unique type name generate by the library to the one passed as an argument.
424424
Has meaning only for `Schema wrapper` implementation.

apollo4.d.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import {DocumentNode, GraphQLSchema} from "graphql";
22
import {ApolloServerPlugin} from '@apollo/server';
33

4+
/**
5+
* Constraint directive typeDef as a `string`
6+
*/
47
export const constraintDirectiveTypeDefs: string;
58

9+
/**
10+
* Constraint directive typeDef as a `DocumentNode`
11+
*/
612
export const constraintDirectiveTypeDefsGql: DocumentNode;
713

8-
export function createApollo4QueryValidationPlugin ( options: { schema: GraphQLSchema } ) : ApolloServerPlugin;
14+
/**
15+
* Create Apollo 4 validation plugin.
16+
*
17+
* @param options to setup plugin. `schema` is deprecated now, not used, as plugins gets schema from the Apollo Server.
18+
*/
19+
export function createApollo4QueryValidationPlugin ( options: { schema?: GraphQLSchema } ) : ApolloServerPlugin;

apollo4.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
const {
22
separateOperations,
3+
buildSchema,
34
GraphQLError
45
} = require('graphql')
56
const { validateQuery } = require('./index')
67
const { constraintDirectiveTypeDefs } = require('./lib/type-defs')
78
const { gql } = require('graphql-tag')
89

9-
function createApollo4QueryValidationPlugin ({ schema }) {
10+
let currentSchema
11+
12+
function createApollo4QueryValidationPlugin () {
1013
return {
14+
async serverWillStart () {
15+
return {
16+
schemaDidLoadOrUpdate ({ apiSchema, coreSupergraphSdl }) {
17+
if (coreSupergraphSdl) { currentSchema = buildSchema(coreSupergraphSdl) } else { currentSchema = apiSchema }
18+
}
19+
}
20+
},
1121
async requestDidStart () {
1222
return ({
1323
async didResolveOperation (requestContext) {
@@ -17,7 +27,7 @@ function createApollo4QueryValidationPlugin ({ schema }) {
1727
: document
1828

1929
const errors = validateQuery(
20-
schema,
30+
currentSchema,
2131
query,
2232
request.variables,
2333
request.operationName

test/setup-apollo4-plugin.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ module.exports = async function ({ typeDefs, formatError, resolvers, schemaCreat
1818
}
1919

2020
const plugins = [
21-
createApollo4QueryValidationPlugin({
22-
schema
23-
})
21+
createApollo4QueryValidationPlugin()
2422
]
2523

2624
const app = express()

0 commit comments

Comments
 (0)