You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+3-324Lines changed: 3 additions & 324 deletions
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,8 @@ GraphQL Java Tools works extremely well if you already have domain POJOs that ho
10
10
11
11
GraphQL Java Tools aims for seamless integration with Java, but works for any JVM language. Try it with Kotlin!
12
12
13
+
Take a look at our new [documentation](https://www.graphql-java-kickstart.com/tools/) for more details.
14
+
13
15
## Why GraphQL Java Tools?
14
16
15
17
***Schema First**: GraphQL Java Tools allows you to write your schema in a simple, portable way using the [GraphQL schema language](http://graphql.org/learn/schema/) instead of hard-to-read builders in code.
@@ -21,32 +23,7 @@ A few libraries exist to ease the boilerplate pain, including [GraphQL-Java's bu
21
23
***Class Validation**: Since there aren't any compile-time checks of the type->class relationship, GraphQL Java Tools will warn you if you provide classes/types that you don't need to, as well as erroring if you use the wrong Java class for a certain GraphQL type when it builds the schema.
22
24
***Unit Testing**: Since your GraphQL schema is independent of your data model, this makes your classes simple and extremely testable.
23
25
24
-
## Usage
25
-
26
-
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
27
-
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
28
-
**Table of Contents**
29
-
30
-
-[Maven/Gradle](#mavengradle)
31
-
-[Examples](#examples)
32
-
-[Defining a Schema](#defining-a-schema)
33
-
-[Resolvers and Data Classes](#resolvers-and-data-classes)
-[Interfaces and Union Types](#interfaces-and-union-types)
39
-
-[Scalar Types](#scalar-types)
40
-
-[Type Dictionary](#type-dictionary)
41
-
-[Making the graphql-java Schema Instance](#making-the-graphql-java-schema-instance)
42
-
-[GraphQL Descriptions](#graphql-descriptions)
43
-
-[GraphQL Deprecations](#graphql-deprecations)
44
-
-[Schema Parser Options](#schema-parser-options)
45
-
46
-
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
47
-
48
-
49
-
### Maven/Gradle
26
+
## Build with Maven or Gradle
50
27
51
28
```xml
52
29
<dependency>
@@ -74,301 +51,3 @@ repositories {
74
51
jcenter()
75
52
}
76
53
```
77
-
78
-
### Examples
79
-
80
-
A working [Java Spring-Boot application](example) is provided, based off the [Star Wars API](https://github.com/graphql-java/graphql-java/blob/master/src/test/groovy/graphql/StarWarsSchema.java) tests and [test data](https://github.com/graphql-java/graphql-java/blob/master/src/test/groovy/graphql/StarWarsData.groovy).
81
-
If you're using Spring Boot, check out the [graphql-spring-boot-starter](https://github.com/graphql-java/graphql-spring-boot)!
82
-
83
-
A working [Kotlin example](src/test/kotlin/com/coxautodev/graphql/tools/EndToEndSpec.kt) can be found in the tests.
84
-
85
-
### Defining a Schema
86
-
87
-
A [GraphQL schema](http://graphql.org/learn/schema/) can be given either as raw strings:
88
-
89
-
```java
90
-
// My application class
91
-
SchemaParser.newParser()
92
-
.schemaString("Query { }")
93
-
```
94
-
95
-
or as files on the classpath:
96
-
97
-
```java
98
-
// My application class
99
-
SchemaParser.newParser()
100
-
.file("my-schema.graphqls")
101
-
102
-
// my-schema.graphqls
103
-
Query { }
104
-
```
105
-
106
-
Multiple sources will be concatenated together in the order given, allowing you to modularize your schema if desired.
107
-
108
-
109
-
### Resolvers and Data Classes
110
-
111
-
GraphQL Java Tools maps fields on your GraphQL objects to methods and properties on your java objects.
112
-
For most scalar fields, a POJO with fields and/or getter methods is enough to describe the data to GraphQL.
113
-
More complex fields (like looking up another object) often need more complex methods with state not provided by the GraphQL context (repositories, connections, etc).
114
-
GraphQL Java Tools uses the concept of "Data Classes" and "Resolvers" to account for both of these situations.
115
-
116
-
Given the following GraphQL schema
117
-
```graphql
118
-
typeQuery {
119
-
books: [Book!]
120
-
}
121
-
122
-
typeBook {
123
-
id: Int!
124
-
name: String!
125
-
author: Author!
126
-
}
127
-
128
-
typeAuthor {
129
-
id: Int!
130
-
name: String!
131
-
}
132
-
```
133
-
134
-
GraphQLJavaToolswillexpecttobegiventhreeclassesthatmaptotheGraphQLtypes: `Query`, `Book`, and `Author`.
135
-
TheDataclassesforBookandAuthoraresimple:
136
-
137
-
```java
138
-
classBook {
139
-
privateintid;
140
-
privateStringname;
141
-
privateintauthorId;
142
-
143
-
// constructor
144
-
145
-
// getId
146
-
// getName
147
-
// getAuthorId
148
-
}
149
-
150
-
classAuthor {
151
-
privateintid;
152
-
privateStringname;
153
-
154
-
// constructor
155
-
156
-
// getId
157
-
// getName
158
-
}
159
-
```
160
-
161
-
But what about the complex fields on `Query` and `Book`?
162
-
These are handled by "Resolvers". Resolvers are object instances that reference the "Data Class" they resolve fields for.
163
-
164
-
The BookResolver might look something like this:
165
-
```java
166
-
classBookResolverimplementsGraphQLResolver<Book>/* This class is a resolver for the Book "Data Class" */ {
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.
181
-
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.
182
-
An optional argument can be defined to inject the `DataFetchingEnvironment`, and must be the last argument.
183
-
184
-
#### Root Resolvers
185
-
186
-
Since the Query/Mutation/Subscription objects are root GraphQL objects, they doesn'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:
Last of all, if the data class implements`java.util.Map` then:
227
-
1.`method get(name)`
228
-
229
-
230
-
*Note:* All reflection discovery is done on startup, and runtime reflection method calls use [reflectasm](https://github.com/EsotericSoftware/reflectasm), which increases performance and unifies stacktraces. No more `InvocationTargetException`!
231
-
232
-
*Note:*`java.util.Optional` can be used for nullable field arguments and nullable return values, and the schema parser will verify that it's not used with non-null field arguments and return values.
233
-
234
-
*Note:* Methods on `java.lang.Object` are excluded from method matching, for example a field named `class` will require a method named `getFieldClass` defined.
235
-
236
-
*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.
237
-
238
-
### Enum Types
239
-
240
-
Enum values are automatically mapped by `Enum#name()`.
241
-
242
-
### Input Objects
243
-
244
-
GraphQL input objects don't need to be provided when parsing the schema - they're inferred from the resolver or data class method at run-time.
245
-
If graphql-java passes a `Map<?, ?>` as an argument, GraphQL Java Tools attempts to marshall the data into the class expected by the method in that argument location.
246
-
247
-
This resolver method's first argument will be marshalled automatically:
248
-
```java
249
-
classQueryextendsGraphQLRootResolver {
250
-
publicintadd(AdditionInputinput) {
251
-
return input.getFirst() + input.getSecond();
252
-
}
253
-
}
254
-
255
-
classAdditionInput {
256
-
privateint first;
257
-
privateint second;
258
-
259
-
// getFirst()
260
-
// getSecond()
261
-
}
262
-
```
263
-
264
-
### Interfaces and Union Types
265
-
266
-
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.
267
-
Although not necessary, it's generally a good idea to have java interfaces that correspond to your GraphQL interfaces to keep your code understandable.
268
-
269
-
### Scalar Types
270
-
271
-
It's possible to create custom scalar types in GraphQL-Java by creating a new instance of the `GraphQLScalarType` class. To use a custom scalar with GraphQL Java Tools, add the scalar to your GraphQL schema:
272
-
```graphql
273
-
scalarUUID
274
-
```
275
-
276
-
Then pass the scalar instance to the parser:
277
-
```java
278
-
SchemaParser.newParser()
279
-
// ...
280
-
.scalars(myUuidScalar)
281
-
```
282
-
283
-
### Type Dictionary
284
-
285
-
Sometimes GraphQL Java Tools can't find classes when it scans your objects, usually because of limitations with interface and union types. Sometimes your Java classes don't line up perfectly with your GraphQL schema, either. GraphQL Java Tools allows you to provide additional classes manually and "rename" them if desired:
After you've passed all relavant schema files/class to the parser, call `.build()` and `.makeExecutableSchema()` to get a graphql-java `GraphQLSchema`:
296
-
297
-
```java
298
-
SchemaParser.newParser()
299
-
// ...
300
-
.build()
301
-
.makeExecutableSchema()
302
-
```
303
-
304
-
If you want to build the `GraphQLSchema` yourself, you can get all of the parsed objects with `parseSchemaObjects()`:
305
-
306
-
```java
307
-
SchemaParser.newParser()
308
-
// ...
309
-
.build()
310
-
.parseSchemaObjects()
311
-
```
312
-
313
-
### GraphQL Descriptions
314
-
315
-
GraphQL object/field/argument descriptions can be provided by comments in the schema:
316
-
317
-
```graphql
318
-
# One of the films in the Star Wars Trilogy
319
-
enumEpisode {
320
-
# Released in 1977
321
-
NEWHOPE
322
-
# Released in 1980
323
-
EMPIRE
324
-
# Released in 1983
325
-
JEDI
326
-
}
327
-
```
328
-
### GraphQL Deprecations
329
-
330
-
GraphQL field/enum deprecations can be provided by the `@deprecated(reason: String)` directive, and are added to the generated schema.
331
-
You can either supply a **reason** argument with a string value or not supply one and receive a "No longer supported" message when introspected:
For advanced use-cases, the schema parser can be tweaked to suit your needs.
352
-
Use `SchemaParserOptions.newBuilder()` to build an options object to pass to the parser.
353
-
354
-
Options:
355
-
*`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<T>`, you must pass `Future.class` and `0`.
356
-
*`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`.
357
-
*`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.
358
-
*`objectMapperConfigurer`: Exposes the Jackson `ObjectMapper` that handles marshalling arguments in method resolvers. Every method resolver gets its own mapper, and the configurer can configure it differently based on the GraphQL field definition.
359
-
*`preferGraphQLResolver`: In cases where you have a Resolver class and legacy class that conflict on type arguements, use the Resolver class instead of throwing an error.
360
-
361
-
Specificly this situation can occur when you have a graphql schema type `Foo` with a `bars` property and classes:
362
-
```java
363
-
// legacy class you can't change
364
-
classFoo {
365
-
Set<Bar>getBars() {...returns set of bars...}
366
-
}
367
-
368
-
// nice resolver that does what you want
369
-
classFooResolverimplementsGraphQLResolver<Foo> {
370
-
Set<BarDTO>getBars() {...converts Bar objects to BarDTO objects and retunrs set...}
371
-
}
372
-
```
373
-
You will now have the code find two different return types for getBars() and application will not start with the error ```Caused by:com.coxautodev.graphql.tools.SchemaClassScannerError:Two different classes used for type```
374
-
Ifthis property is true it will ignore the legacy version.
0 commit comments