diff --git a/content/tools/directives/index.md b/content/tools/directives/index.md index 8d09a2d..ab5da66 100644 --- a/content/tools/directives/index.md +++ b/content/tools/directives/index.md @@ -68,9 +68,12 @@ Arguments the SDL leaves out are filled in with their default from the directive An enum that's only used by directive definitions doesn't need a Java class. Its values are then passed to the wiring as `String`s. Add the enum to the [type dictionary]({{< relref "/tools/schema-definition/index.md#type-dictionary" >}}) to get the enum constants instead. +Wirings run once the whole schema is built, like in graphql-java, so the types they see are the real ones and not `GraphQLTypeReference`s. + ## Supported locations -Support for directives is currently limited to the following locations: +Wirings run for directives on the following locations: +* `SCALAR` * `OBJECT` * `FIELD_DEFINITION` * `ARGUMENT_DEFINITION` @@ -81,8 +84,6 @@ Support for directives is currently limited to the following locations: * `INPUT_OBJECT` * `INPUT_FIELD_DEFINITION` -Meaning directives for the following locations are currently not yet supported: - -* `SCALAR` +A directive applied where its definition doesn't allow it, without a required argument, or more than once without being `repeatable` logs a warning. These will fail the build in 15.0.0. Directives on `schema` and `extend schema` don't run a wiring, but they're added to the schema's applied directives. Like everywhere else, they have to be declared, unless `allowUndeclaredDirectives` is set in the [schema parser options]({{< relref "/tools/schema-parser-options/index.md" >}}). diff --git a/content/tools/getting-started/index.md b/content/tools/getting-started/index.md index 1962b3f..f80bba2 100644 --- a/content/tools/getting-started/index.md +++ b/content/tools/getting-started/index.md @@ -34,7 +34,7 @@ Add the `graphql-java-tools` dependency: ```gradle dependencies { - implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.3.0' + implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.4.0' } ``` @@ -46,7 +46,7 @@ Add the `graphql-java-tools` dependency: io.github.graphql-java-kickstart graphql-java-tools - 14.3.0 + 14.4.0 ``` diff --git a/content/tools/schema-definition/index.md b/content/tools/schema-definition/index.md index fd99a46..bd10454 100644 --- a/content/tools/schema-definition/index.md +++ b/content/tools/schema-definition/index.md @@ -108,7 +108,8 @@ class BookResolver implements GraphQLResolver /* This class is a resolver When given a `BookResolver` instance, GraphQL Java Tools first attempts to map fields to methods on the resolver before mapping them to fields or methods on the data class. If there is a matching method on the resolver, the data class instance is passed as the first argument to the resolver function. This does not apply to root resolvers, since those don't have a data class to resolve for. -An optional parameter can be defined to inject the `DataFetchingEnvironment`, and must be the last argument. +The field's arguments come next, in order. +After them, a method can take any of `DataFetchingEnvironment`, `GraphQLContext` and the `contextClass` set in the [schema parser options]({{< relref "/tools/schema-parser-options/index.md" >}}), in any order. A resolver also applies to subclasses and implementations of its data class, so a `GraphQLResolver` resolves fields for a data class `Thing extends Base`. A resolver for a generic class, like `GraphQLResolver>`, applies to every `Page`. @@ -150,24 +151,32 @@ SchemaParser.newParser() The field mapping is done by name against public/protected methods and public/protected/private fields, with the following priority: +`*environmentOrContext` stands for any of `DataFetchingEnvironment`, `GraphQLContext` and the `contextClass`, in any order. + First on the resolver or root resolver (note that dataClassInstance doesn't apply for root resolvers): -1. `method (dataClassInstance, *fieldArgs [, DataFetchingEnvironment])` -2. `method is(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])`, only if the field returns a `Boolean` -3. `method get(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])` -4. `method getField(dataClassInstance, *fieldArgs [, DataFetchingEnvironment])` +1. `method (dataClassInstance, *fieldArgs [, *environmentOrContext])` +2. `method is(dataClassInstance, *fieldArgs [, *environmentOrContext])`, only if the field returns a `Boolean` +3. `method get(dataClassInstance, *fieldArgs [, *environmentOrContext])` +4. `method getField(dataClassInstance, *fieldArgs [, *environmentOrContext])` Then on the data class: -1. `method (*fieldArgs [, DataFetchingEnvironment])` -2. `method is(*fieldArgs [, DataFetchingEnvironment])`, only if the field returns a `Boolean` -3. `method get(*fieldArgs [, DataFetchingEnvironment])` -4. `method getField(*fieldArgs [, DataFetchingEnvironment])` +1. `method (*fieldArgs [, *environmentOrContext])` +2. `method is(*fieldArgs [, *environmentOrContext])`, only if the field returns a `Boolean` +3. `method get(*fieldArgs [, *environmentOrContext])` +4. `method getField(*fieldArgs [, *environmentOrContext])` 5. `field ` Last of all, if the data class implements`java.util.Map` then: 1. `method get(name)` +If nothing above matches, a resolver method can leave out the data class instance, as long as it ends in at least one environment or context parameter: + +1. `method (*fieldArgs, *environmentOrContext)`, and the `is`, `get` and `getField` forms in the same order as above + +This is for fields that only need the environment, e.g. a value the parent field put in its `localContext`. It doesn't apply when `allowUnimplementedResolvers` or a missing resolver data fetcher is set, since those already handle a field with no match. + diff --git a/content/tools/schema-parser-options/index.md b/content/tools/schema-parser-options/index.md index d381efe..00f42e2 100644 --- a/content/tools/schema-parser-options/index.md +++ b/content/tools/schema-parser-options/index.md @@ -24,6 +24,8 @@ Options: ``` * `genericWrappers`: Allows defining your own generic classes that should be unwrapped when matching Java types to GraphQL types. You must supply the class and the index (zero-indexed) of the wrapped generic type. For example: If you want to unwrap type argument `T` of `Future`, you must pass `Future.class` and `0`. Use `GenericWrapper.withTransformer` to also convert the value at runtime. If the transformer returns `null`, the field is `null`. + Wrappers and futures nested in lists or in other wrappers are unwrapped too, e.g. `List>` or `List>`. If one element fails, the whole field fails. + A transformer or nested future that calls a DataLoader after an async step needs graphql-java's DataLoader chaining (`DataLoaderDispatchingContextKeys.setEnableDataLoaderChaining`), otherwise the field never completes. * `useDefaultGenericWrappers`: Defaults to `true`. Tells the parser whether or not to add it's own list of well-known generic wrappers, such as `Future` and `CompletableFuture`. graphql-java only waits on a `CompletionStage`, so a method declared to return a `Future` has to return one, such as a `CompletableFuture`. Any other future fails the field with an error, unless a generic wrapper transformer converts it.