diff --git a/content/tools/_index.md b/content/tools/_index.md
index 6b1130a..47a7020 100644
--- a/content/tools/_index.md
+++ b/content/tools/_index.md
@@ -8,8 +8,8 @@ menu:
parent: Tools
---
-[](https://maven-badges.herokuapp.com/maven-central/com.graphql-java-kickstart/graphql-java-tools)
-[](https://travis-ci.org/graphql-java-kickstart/graphql-java-tools)
+[](https://central.sonatype.com/artifact/io.github.graphql-java-kickstart/graphql-java-tools)
+[](https://github.com/graphql-java-kickstart/graphql-java-tools/actions/workflows/snapshot.yml)
[](https://sonarcloud.io/dashboard?id=graphql-java-kickstart_graphql-java-tools)
[](https://github.com/graphql-java-kickstart/graphql-java-tools/graphs/contributors)
[](https://github.com/graphql-java-kickstart/graphql-java-tools/discussions)
diff --git a/content/tools/directives/index.md b/content/tools/directives/index.md
index 22427a1..c4cd3dc 100644
--- a/content/tools/directives/index.md
+++ b/content/tools/directives/index.md
@@ -9,7 +9,7 @@ menu:
url: /tools/directives/
---
-See [Schema Directives](https://www.graphql-java.com/documentation/v16/sdl-directives/)
+See [Schema Directives](https://www.graphql-java.com/documentation/directives)
for a detailed explanation about directives including examples on how to define
them in the SDL and to create the required classes.
@@ -67,6 +67,12 @@ SchemaParser.newParser()
.makeExecutableSchema();
```
+If several wirings apply to the same element, each one gets the element returned by the previous one.
+
+Arguments the SDL leaves out are filled in with their default from the directive definition, so the wiring sees the default instead of `null`.
+
+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.
+
## Supported locations
Support for directives is currently limited to the following locations:
@@ -83,3 +89,5 @@ Support for directives is currently limited to the following locations:
Meaning directives for the following locations are currently not yet supported:
* `SCALAR`
+
+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 9b9b832..1962b3f 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 {
- compile 'com.graphql-java-kickstart:graphql-java-tools:13.0.3'
+ implementation 'io.github.graphql-java-kickstart:graphql-java-tools:14.3.0'
}
```
@@ -44,15 +44,15 @@ Add the `graphql-java-tools` dependency:
```xml
- com.graphql-java-kickstart
+ io.github.graphql-java-kickstart
graphql-java-tools
- 13.0.3
+ 14.3.0
```
## Using the latest development build
-Snapshot versions of the current `master` branch are available on JFrog. Check the next snapshot version on
+Snapshot versions of the current `master` branch are available on the Maven Central snapshot repository. Check the next snapshot version on
[Github](https://github.com/graphql-java-kickstart/graphql-java-tools/blob/master/pom.xml#L7)
### Build with Gradle
@@ -62,7 +62,7 @@ Add the Snapshot repository:
```gradle
repositories {
mavenCentral()
- maven { url "https://oss.jfrog.org/artifactory/oss-snapshot-local" }
+ maven { url = 'https://central.sonatype.com/repository/maven-snapshots/' }
}
```
@@ -73,9 +73,12 @@ Add the Snapshot repository:
```xml
- oss-snapshot-local
- jfrog
- https://oss.jfrog.org/artifactory/oss-snapshot-local
+ central-portal-snapshots
+ Central Portal Snapshots
+ https://central.sonatype.com/repository/maven-snapshots/
+
+ false
+
true
always
diff --git a/content/tools/schema-definition/index.md b/content/tools/schema-definition/index.md
index dcc4857..fd99a46 100644
--- a/content/tools/schema-definition/index.md
+++ b/content/tools/schema-definition/index.md
@@ -28,6 +28,12 @@ SchemaParser.newParser()
Query { }
```
Multiple sources will be concatenated together in the order given, allowing you to modularize your schema if desired.
+Line numbers in syntax errors count from the start of each file or string, and errors in a file end with its name. To name a schema string too, pass the name as well:
+
+```java
+SchemaParser.newParser()
+ .schemaString(usersSchema, "users.graphqls")
+```
## Resolvers and Data Classes
@@ -104,6 +110,17 @@ When given a `BookResolver` instance, GraphQL Java Tools first attempts to map f
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.
+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`.
+When several resolvers apply, the one for the most specific type is tried first.
+
+In Kotlin, a resolver method can also be an extension function on the data class:
+```kotlin
+class BookResolver(private val authorRepository: AuthorRepository) : GraphQLResolver {
+ fun Book.author(): Author = authorRepository.findById(authorId)
+}
+```
+
### Root Resolvers
Since the Query/Mutation/Subscription objects are root GraphQL objects, they don't have an associated data class. In those cases, any resolvers implementing `GraphQLQueryResolver`, `GraphQLMutationResolver`, or `GraphQLSubscriptionResolver` will be searched for methods that map to fields in their respective root types. Root resolver methods can be spread between multiple resolvers, but a simple example is below:
@@ -156,7 +173,7 @@ Last of all, if the data class implements`java.util.Map` then:
*Note:* Methods on `java.lang.Object` are excluded from method matching, for example a field named `class` will require a method named `getFieldClass` defined.
-*Note:* If one of the values of a type backed by a `java.util.Map` is non-scalar then this type will need to be added to the `type dictionary` (see below). After adding this type to the dictionary, GraphQL Java Tools will however still be able to find the types used in the fields of this added type.
+*Note:* If one of the values of a type backed by a `java.util.Map` is non-scalar, on its own or in a list, then this type will need to be added to the `type dictionary` (see below). After adding this type to the dictionary, GraphQL Java Tools will however still be able to find the types used in the fields of this added type.
## Enum Types
@@ -187,6 +204,7 @@ class AdditionInput {
## Interfaces and Union Types
GraphQL interface/union types are automatically resolved from the schema and the list of provided classes, and require no extra work outside of the schema.
+Members and implementors that no resolver returns need to be in the [type dictionary](#type-dictionary), unless the class of their union or interface is sealed.
Although not necessary, it's generally a good idea to have java interfaces that correspond to your GraphQL interfaces to keep your code understandable.
## Scalar Types
@@ -213,6 +231,17 @@ SchemaParser.newParser()
.dictionary("Book", BookClassWithIncorrectName.class)
```
+Several input types can share a class, e.g. Jackson's `ObjectNode`. Other types need a class each.
+
+If the class of a union or interface is a Kotlin sealed class or interface, or a Java sealed type, its members and implementors don't need to be added. GraphQL Java Tools uses the subclass with the same simple name as the GraphQL type:
+```kotlin
+// union Pet = NormalPet | WeirdPet
+sealed class Pet {
+ data class NormalPet(val name: String) : Pet()
+ data class WeirdPet(val classification: String) : Pet()
+}
+```
+
## Making the graphql-java Schema Instance
After you've passed all relevant schema files/class to the parser, call `.build()` and `.makeExecutableSchema()` to get a graphql-java `GraphQLSchema`:
diff --git a/content/tools/schema-parser-options/index.md b/content/tools/schema-parser-options/index.md
index 02b59e8..d381efe 100644
--- a/content/tools/schema-parser-options/index.md
+++ b/content/tools/schema-parser-options/index.md
@@ -23,8 +23,10 @@ Options:
.graphQLContext(Map.of(CustomContext.class, context));
```
* `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`.
* `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.
* `allowUnimplementedResolvers`: Defaults to `false`. Allows a schema to be created even if not all GraphQL fields have resolvers. Intended only for development, it will log a warning to remind you to turn it off for production. Any unimplemented resolvers will throw errors when queried.
* `missingResolverDataFetcher`: Allows you to provide custom behavior for missing GraphQL fields.
* `inputArgumentOptionalDetectOmission`: Defaults to `false`. By default, the parser will treat omitted or null method input arguments as `Optional.empty` in resolvers. If you prefer, you can disable this behavior.
@@ -53,8 +55,19 @@ Options:
* Guice
* Spring AOP
* Weld
-* `introspectionEnabled`: Defaults to `true`. When set to `false` this option will disable schema introspection via `NO_INTROSPECTION_FIELD_VISIBILITY`. See [Field Visibility](https://www.graphql-java.com/documentation/master/fieldvisibility/).
-* `fieldVisibility`: Provide a graphql field visibility implementation. This option overrides `introspectionEnabled` when used. See [Field Visibility](https://www.graphql-java.com/documentation/master/fieldvisibility/).
+* `introspectionEnabled`: Defaults to `true`. When set to `false` this option will disable schema introspection via `NO_INTROSPECTION_FIELD_VISIBILITY`. See [Field Visibility](https://www.graphql-java.com/documentation/field-visibility).
+* `fieldVisibility`: Provide a graphql field visibility implementation. This option overrides `introspectionEnabled` when used. See [Field Visibility](https://www.graphql-java.com/documentation/field-visibility).
* `coroutineContext` / `coroutineContextProvider`: Provide a kotlin coroutine context to be used with suspend functions of resolvers.
+ A suspend function runs on the calling thread until it first suspends, and continues on this context after that, so wrap blocking calls in `withContext(Dispatchers.IO)`.
+ To run them in your own `CoroutineScope`, e.g. to cancel them with the request, put it in the execution input's context:
+ ```java
+ var executionInput = ExecutionInput.newExecutionInput()
+ .query(query)
+ .graphQLContext(Map.of(CoroutineScope.class, scope));
+ ```
* `typeDefinitionFactory`: See [Type Definition Factory]({{< relref "/tools/type-definition-factory/index.md" >}}).
* `includeUnusedTypes`: Defaults to `false`. By default, the parser will ignore unused type definitions in the schema. Enable this option to include them regardless.
+* `allowUndeclaredDirectives`: Defaults to `false`. Allows applying directives that aren't declared in the schema, e.g. the Apollo Federation directives imported through `@link`. They're only added as applied directives, with argument types guessed from their values. Directives with enum or input object arguments still have to be declared.
+* `unmappedInputFields`: Defaults to `WARN`. What to do about input type fields that the class of a resolver argument has no property for. When a client sends such a field, Jackson fails to convert the argument, or drops the value if the `ObjectMapper` ignores unknown properties.
+ The classes are checked when the schema is built, with each field's own `ObjectMapper`, and `WARN` logs a warning for each of these fields. `FAIL` fails the build instead, and `IGNORE` skips the check. To leave a field unmapped on purpose, add it to `@JsonIgnoreProperties` on the class.
+ Classes with a custom deserializer, a builder or a delegating creator aren't checked, and neither are arguments bound to a `Map` or a `JsonNode`.