Skip to content

Commit b3d98d6

Browse files
committed
fix(visitAllArgs): problem with Apollo-Server 2 and Introspection
got error: Error: The introspection query is resolving asynchronously; execution of an introspection query is not expected to return a `Promise`. Wrapped type resolvers should maintain the existing execution dynamics of the resolvers they wrap (i.e. async vs sync) or introspection types should be excluded from wrapping by checking them with `graphql/type`s, `isIntrospectionType` predicate function prior to wrapping.
1 parent 7d7b025 commit b3d98d6

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ npm install graphql-middleware-typed-arguments
1818
- 🛴 Half automatic.
1919
- 🏆 Works with every GraphQL server.
2020

21+
## Notes
22+
23+
If you would appreciate an integration of the [Yup validation framework](https://github.com/jquense/yup) to validate your scalar and object-type arguments, look at [this package](https://www.npmjs.com/package/graphql-yup-middleware).
24+
2125
## Demo
2226

2327
The example is taken directly from graphql-middleware-apollo-upload-server which was basis for this generalization. There are two changes from the original: the GraphQLUpload type object is imported, but the type name "Upload" could be used as well. (In fact, type names are simpler way to get at a type defined in SDL.) The second change is providing the type (object or string) to the middleware factory function provided by this package: `processTypeArgs`. (The previous version's `upload` method has been preseved and implemented as a special case.)

package.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"repository": "https://github.com/tgerk/graphql-middleware-typed-arguments",
1414
"author": "Tim Gerk <[email protected]>, Matic Zavadlal <[email protected]>",
1515
"scripts": {
16-
"prepublish": "npm run test",
16+
"prepare": "npm run test",
1717
"test": "npm run lint && npm run build && npm run test-ava",
1818
"lint": "tslint --project tsconfig.json {src}/**/*.ts && prettier-check --ignore-path .gitignore src{,/**}/{*.ts,*.js}",
1919
"build": "rm -rf dist && tsc -d",
@@ -44,5 +44,21 @@
4444
"release": {
4545
"branch": "master"
4646
},
47+
"homepage": "https://github.com/tgerk/graphql-middleware-typed-arguments",
48+
"repository": {
49+
"type": "git",
50+
"url": "https://github.com/tgerk/graphql-middleware-typed-arguments.git"
51+
},
52+
"bugs": {
53+
"url": "https://github.com/tgerk/graphql-middleware-typed-arguments/issues"
54+
},
55+
"keywords": [
56+
"graphql",
57+
"middleware",
58+
"arguments",
59+
"resolvers",
60+
"server",
61+
"yoga"
62+
],
4763
"license": "MIT"
4864
}

src/index.ts

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
GraphQLArgument,
44
getNamedType,
55
GraphQLNamedType,
6+
isIntrospectionType,
67
} from 'graphql'
78
import { IMiddlewareFunction } from 'graphql-middleware'
89

@@ -46,6 +47,12 @@ function getFieldArguments(info: GraphQLResolveInfo): GraphQLArgument[] {
4647
return typeFields[fieldName].args
4748
}
4849

50+
function fieldHasIntrospectionType(info) {
51+
const { fieldName, parentType } = info
52+
const typeFields = parentType.getFields()
53+
return isIntrospectionType(typeFields[fieldName].type)
54+
}
55+
4956
/**
5057
*
5158
* @param type
@@ -153,6 +160,7 @@ export function makeArgumentTransform<T, V>(
153160
}
154161

155162
return null // exclude arguments when no value provided
163+
// (undefined is changed to null, because TypeScript)
156164
}
157165
}
158166

@@ -212,25 +220,28 @@ export function processTypeArgs<V, T>({
212220

213221
export function visitAllArgs({ transform }): IMiddlewareFunction {
214222
return (resolve, parent, args, ctx, info) => {
215-
const argDefs = getFieldArguments(info)
216-
if (argDefs.length) {
217-
// Apply argument transform function to all arguments
218-
// The caller's transform function is applied to values that may be embedded
219-
// in lists and promises, but not to null or undefined values
220-
// Finally the resolver is called with transformed argument values
221-
return (
222-
Promise.all(
223-
filterMap(
224-
makeArgumentTransform(transform, parent, args, ctx, info),
225-
argDefs,
226-
),
227-
)
228-
// substitute the transformed values into the args object
229-
.then(newArgs =>
230-
newArgs.reduce((args, newArg) => ({ ...args, ...newArg }), args),
223+
// TODO avoid introspection types--very fussy about introducing async into sync code
224+
if (!fieldHasIntrospectionType(info)) {
225+
const argDefs = getFieldArguments(info)
226+
if (argDefs.length) {
227+
// Apply argument transform function to all arguments
228+
// The caller's transform function is applied to values that may be embedded
229+
// in lists and promises, but not to null or undefined values
230+
// Finally the resolver is called with transformed argument values
231+
return (
232+
Promise.all(
233+
filterMap(
234+
makeArgumentTransform(transform, parent, args, ctx, info),
235+
argDefs,
236+
),
231237
)
232-
.then(newArgs => resolve(parent, newArgs, ctx, info))
233-
)
238+
// substitute the transformed values into the args object
239+
.then(newArgs =>
240+
newArgs.reduce((args, newArg) => ({ ...args, ...newArg }), args),
241+
)
242+
.then(newArgs => resolve(parent, newArgs, ctx, info))
243+
)
244+
}
234245
}
235246

236247
return resolve(parent, args, ctx, info)

0 commit comments

Comments
 (0)