-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.json
1 lines (1 loc) · 42.3 KB
/
index.json
1
[{"categories":null,"contents":"A working version of this example can be found at https://github.com/graphql-java-kickstart/samples/tree/master/servlet-hello-world.\nBuild with Gradle First you set up a basic build script. You can use any build system you like, but the code you need to work with Gradle and Maven is included here.\nCreate a Gradle build file Make sure mavenCentral is among your repositories. The example build script below uses org.gretty to provide a webserver to show a working example.\nplugins { id \u0026#39;war\u0026#39; id \u0026#39;idea\u0026#39; id \u0026#39;org.gretty\u0026#39; version \u0026#39;2.2.0\u0026#39; } repositories { mavenCentral() } dependencies { compile \u0026#39;com.graphql-java-kickstart:graphql-java-servlet:15.0.0\u0026#39; } Build with Maven First you set up a basic build script. You can use any build system you like, but the code you need to work with Gradle and Maven is included here. We\u0026rsquo;re assuming you already have a basic understanding of the build system of your choosing and how to use it. So instead of providing fully functioning build script we only provide the sections needed to add graphql-java-servlet to your application.\nUpdate your Maven pom file Add the graphql-java-servlet dependency to your dependencies section:\n\u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.graphql-java-kickstart\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;graphql-java-servlet\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;15.0.0\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; Create a Servlet class Create a servlet class extending SimpleGraphQLHttpServlet. This is the basic \u0026ldquo;Hello world\u0026rdquo; example. It creates the GraphQL Query { hello } that can be executed and which will respond with \u0026ldquo;world\u0026rdquo;. It creates the GraphQL schema programmatically as shown in the getting started example from graphql-java.\n@WebServlet(name = \u0026#34;HelloServlet\u0026#34;, urlPatterns = {\u0026#34;graphql/*\u0026#34;}, loadOnStartup = 1) public class HelloServlet extends GraphQLHttpServlet { @Override protected GraphQLConfiguration getConfiguration() { return GraphQLConfiguration.with(createSchema()).build(); } private GraphQLSchema createSchema() { String schema = \u0026#34;type Query{hello: String}\u0026#34;; SchemaParser schemaParser = new SchemaParser(); TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema); RuntimeWiring runtimeWiring = newRuntimeWiring() .type(\u0026#34;Query\u0026#34;, builder -\u0026gt; builder.dataFetcher(\u0026#34;hello\u0026#34;, new StaticDataFetcher(\u0026#34;world\u0026#34;))) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring); } } Run the application To run the application, execute the gradle appRun task that was added by org.gretty. If all goes well it will start a jetty webserver and expose the Hello world Servlet on localhost. It will log the exact endpoint, like below:\n17:45:53 INFO Jetty 9.2.24.v20180105 started and listening on port 8080 17:45:53 INFO graphql-java-servlet-hello-world runs at: 17:45:53 INFO http://localhost:8080/graphql-java-servlet-hello-world \u0026gt; Task :graphql-java-servlet-hello-world:appRun Press any key to stop the server. Send a GraphQL Query You can now send a GraphQL query to your local servlet, for example using Insomnia. In this case the URL to post the GraphQL query to is http://localhost:8080/graphql-java-servlet-hello-world/graphql.\nThe following GraphQL query is what the example implementation supports:\nquery { hello } Our Hello Servlet will respond with:\n{ \u0026#34;data\u0026#34;: { \u0026#34;hello\u0026#34;: \u0026#34;world\u0026#34; } } ","permalink":"https://graphql-java-kickstart.github.io/servlet/getting-started/","tags":null,"title":"Getting started"},{"categories":null,"contents":"This project requires at least the following version:\n Java 17 Spring Boot 3.x.x (spring-boot-starter-web) Quick start To add graphql-spring-boot to your project and get started quickly, do the following.\nBuild with Gradle Make sure mavenCentral is amongst your repositories:\nrepositories { mavenCentral() } Add the respective starter dependencies you want to use:\ndependencies { implementation \u0026#39;com.graphql-java-kickstart:graphql-spring-boot-starter:15.0.0\u0026#39; // testing facilities testImplementation \u0026#39;com.graphql-java-kickstart:graphql-spring-boot-starter-test:15.0.0\u0026#39; } Build with Maven Add the respective starter dependencies you want to use:\n\u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.graphql-java-kickstart\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;graphql-spring-boot-starter\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;15.0.0\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!-- testing facilities --\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.graphql-java-kickstart\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;graphql-spring-boot-starter-test\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;15.0.0\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; Using the latest development build Snapshot versions of the current master branch are available on JFrog. Check the next snapshot version on Github\nBuild with Gradle Add the Snapshot repository:\nrepositories { mavenCentral() maven { url \u0026#34;https://oss.jfrog.org/artifactory/oss-snapshot-local\u0026#34; } } Build with Maven Add the Snapshot repository:\n\u0026lt;repositories\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;oss-snapshot-local\u0026lt;/id\u0026gt; \u0026lt;name\u0026gt;jfrog\u0026lt;/name\u0026gt; \u0026lt;url\u0026gt;https://oss.jfrog.org/artifactory/oss-snapshot-local\u0026lt;/url\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;updatePolicy\u0026gt;always\u0026lt;/updatePolicy\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;/repositories\u0026gt; ","permalink":"https://graphql-java-kickstart.github.io/spring-boot/getting-started/","tags":null,"title":"Getting started"},{"categories":null,"contents":"A working Java Spring-Boot application is provided, based off the Star Wars API tests and test data. If you\u0026rsquo;re using Spring Boot, check out the graphql-spring-boot-starter!\nA working Kotlin example can be found in the tests.\nQuick start To add graphql-java-tools to your project and get started quickly, do the following.\nBuild with Gradle Make sure mavenCentral is amongst your repositories:\nrepositories { mavenCentral() } Add the graphql-java-tools dependency:\ndependencies { compile \u0026#39;com.graphql-java-kickstart:graphql-java-tools:13.0.3\u0026#39; } Build with Maven Add the graphql-java-tools dependency:\n\u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;com.graphql-java-kickstart\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;graphql-java-tools\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;13.0.3\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; Using the latest development build Snapshot versions of the current master branch are available on JFrog. Check the next snapshot version on Github\nBuild with Gradle Add the Snapshot repository:\nrepositories { mavenCentral() maven { url \u0026#34;https://oss.jfrog.org/artifactory/oss-snapshot-local\u0026#34; } } Build with Maven Add the Snapshot repository:\n\u0026lt;repositories\u0026gt; \u0026lt;repository\u0026gt; \u0026lt;id\u0026gt;oss-snapshot-local\u0026lt;/id\u0026gt; \u0026lt;name\u0026gt;jfrog\u0026lt;/name\u0026gt; \u0026lt;url\u0026gt;https://oss.jfrog.org/artifactory/oss-snapshot-local\u0026lt;/url\u0026gt; \u0026lt;snapshots\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;updatePolicy\u0026gt;always\u0026lt;/updatePolicy\u0026gt; \u0026lt;/snapshots\u0026gt; \u0026lt;/repository\u0026gt; \u0026lt;/repositories\u0026gt; ","permalink":"https://graphql-java-kickstart.github.io/tools/getting-started/","tags":null,"title":"Getting started"},{"categories":null,"contents":"It is possible to create context, and consequently dataloaders, in both a request scope and a per query scope by customizing GraphQLContextBuilder and selecting the appropriate ContextSetting with the provided GraphQLConfiguration. A new DataLoaderRegistry should be created in each call to the GraphQLContextBuilder, and the servlet will call the builder at the appropriate times. For example:\npublic class CustomGraphQLContextBuilder implements GraphQLServletContextBuilder { private final DataLoader userDataLoader; public CustomGraphQLContextBuilder(DataLoader userDataLoader) { this.userDataLoader = userDataLoader; } public GraphQLContext build() { return new DefaultGraphQLContext(); } public GraphQLContext build(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { return DefaultGraphQLServletContext.createServletContext() .with(httpServletRequest) .with(httpServletResponse) .with(buildDataLoaderRegistry()) .build(); } public GraphQLContext build(Session session, HandshakeRequest handshakeRequest) { return DefaultGraphQLWebSocketContext.createWebSocketContext() .with(session) .with(handshakeRequest) .with(buildDataLoaderRegistry()) .build(); } private DataLoaderRegistry buildDataLoaderRegistry() { DataLoaderRegistry registry = new DataLoaderRegistry(); registry.register(\u0026#34;userDataLoader\u0026#34;, userDataLoader); return registry; } } It is then possible to access the DataLoader in the resolvers by accessing the DataLoaderRegistry from context. For example:\npublic CompletableFuture\u0026lt;String\u0026gt; getEmailAddress(User user, DataFetchingEnvironment dfe) { // User is the graphQL type final DataLoader\u0026lt;String, UserDetail\u0026gt; userDataloader = dfe.getContext().getDataLoaderRegistry().get().getDataLoader(\u0026#34;userDataLoader\u0026#34;); // UserDetail is the data that is loaded return userDataloader.load(User.getName()) .thenApply(userDetail -\u0026gt; userDetail != null ? userDetail.getEmailAddress() : null); } If per request is selected this will cause all queries within the http request, if using a batch, to share dataloader caches and batch together load calls as efficiently as possible. The dataloaders are dispatched using instrumentation and the correct instrumentation will be selected according to the ContextSetting. The default context setting in GraphQLConfiguration is per query.\nTwo additional context settings are provided, one for each of the previous settings but without the addition of the Dataloader dispatching instrumentation. This is useful for those not using Dataloaders or wanting to supply their own dispatching instrumentation though the instrumentation supplier within the GraphQLQueryInvoker.\n","permalink":"https://graphql-java-kickstart.github.io/servlet/dataloaders/","tags":null,"title":"Dataloaders"},{"categories":null,"contents":"A GraphQL schema can be given either as raw strings:\n// My application class SchemaParser.newParser() .schemaString(\u0026#34;Query { }\u0026#34;) or as files on the classpath:\n// My application class SchemaParser.newParser() .file(\u0026#34;my-schema.graphqls\u0026#34;) // my-schema.graphqls Query { } Multiple sources will be concatenated together in the order given, allowing you to modularize your schema if desired.\nResolvers and Data Classes GraphQL Java Tools maps fields on your GraphQL objects to methods and properties on your java objects. For most scalar fields, a POJO with fields and/or getter methods is enough to describe the data to GraphQL. More complex fields (like looking up another object) often need more complex methods with state not provided by the GraphQL context (repositories, connections, etc). GraphQL Java Tools uses the concept of \u0026ldquo;Data Classes\u0026rdquo; and \u0026ldquo;Resolvers\u0026rdquo; to account for both of these situations.\nGiven the following GraphQL schema\ntype Query { books: [Book!] } type Book { id: Int! name: String! author: Author! } type Author { id: Int! name: String! } GraphQL Java Tools will expect to be given three classes that map to the GraphQL types: Query, Book, and Author. The Data classes for Book and Author are simple:\nclass Book { private int id; private String name; private int authorId; // constructor // getId // getName // getAuthorId } class Author { private int id; private String name; // constructor // getId // getName } What about the complex fields on Query and Book? These are handled by \u0026ldquo;Resolvers\u0026rdquo;. Resolvers are object instances that reference the \u0026ldquo;Data Class\u0026rdquo; they resolve fields for.\nThe BookResolver might look something like this:\nclass BookResolver implements GraphQLResolver\u0026lt;Book\u0026gt; /* This class is a resolver for the Book \u0026#34;Data Class\u0026#34; */ { private AuthorRepository authorRepository; public BookResolver(AuthorRepository authorRepository) { this.authorRepository = authorRepository; } public Author author(Book book) { return authorRepository.findById(book.getAuthorId()); } } 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\u0026rsquo;t have a data class to resolve for. An optional parameter can be defined to inject the DataFetchingEnvironment, and must be the last argument.\nRoot Resolvers Since the Query/Mutation/Subscription objects are root GraphQL objects, they don\u0026rsquo;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:\nclass Query implements GraphQLQueryResolver { private BookRepository bookRepository; public Query(BookRepository bookRepository) { this.bookRepository = bookRepository; } public List\u0026lt;Book\u0026gt; books() { return bookRepository.findAll(); } } Resolvers must be provided to the schema parser:\nSchemaParser.newParser() // ... .resolvers(new Query(bookRepository), new BookResolver(authorRepository)) Field Mapping Priority The field mapping is done by name against public/protected methods and public/protected/private fields, with the following priority:\nFirst on the resolver or root resolver (note that dataClassInstance doesn\u0026rsquo;t apply for root resolvers):\n method \u0026lt;name\u0026gt;(dataClassInstance, *fieldArgs [, DataFetchingEnvironment]) method is\u0026lt;Name\u0026gt;(dataClassInstance, *fieldArgs [, DataFetchingEnvironment]), only if the field returns a Boolean method get\u0026lt;Name\u0026gt;(dataClassInstance, *fieldArgs [, DataFetchingEnvironment]) method getField\u0026lt;Name\u0026gt;(dataClassInstance, *fieldArgs [, DataFetchingEnvironment]) Then on the data class:\n method \u0026lt;name\u0026gt;(*fieldArgs [, DataFetchingEnvironment]) method is\u0026lt;Name\u0026gt;(*fieldArgs [, DataFetchingEnvironment]), only if the field returns a Boolean method get\u0026lt;Name\u0026gt;(*fieldArgs [, DataFetchingEnvironment]) method getField\u0026lt;Name\u0026gt;(*fieldArgs [, DataFetchingEnvironment]) field \u0026lt;name\u0026gt; Last of all, if the data class implementsjava.util.Map then:\n method get(name) Note: Methods on java.lang.Object are excluded from method matching, for example a field named class will require a method named getFieldClass defined.\nNote: 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.\nEnum Types Enum values are automatically mapped by Enum#name().\nInput Objects GraphQL input objects don\u0026rsquo;t need to be provided when parsing the schema - they\u0026rsquo;re inferred from the resolver or data class method at run-time. If graphql-java passes a Map\u0026lt;?, ?\u0026gt; as an argument, GraphQL Java Tools attempts to marshall the data into the class expected by the method in that argument location.\nThis resolver method\u0026rsquo;s first argument will be marshalled automatically:\nclass Query extends GraphQLRootResolver { public int add(AdditionInput input) { return input.getFirst() + input.getSecond(); } } class AdditionInput { private int first; private int second; // getFirst() // getSecond() } 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. Although not necessary, it\u0026rsquo;s generally a good idea to have java interfaces that correspond to your GraphQL interfaces to keep your code understandable.\nScalar Types It\u0026rsquo;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:\nscalar UUID Then pass the scalar instance to the parser:\nSchemaParser.newParser() // ... .scalars(myUuidScalar) Type Dictionary Sometimes GraphQL Java Tools can\u0026rsquo;t find classes when it scans your objects, usually because of limitations with interface and union types. Sometimes your Java classes don\u0026rsquo;t line up perfectly with your GraphQL schema, either. GraphQL Java Tools allows you to provide additional classes manually and \u0026ldquo;rename\u0026rdquo; them if desired:\nSchemaParser.newParser() // ... .dictionary(Author.class) .dictionary(\u0026#34;Book\u0026#34;, BookClassWithIncorrectName.class) Making the graphql-java Schema Instance After you\u0026rsquo;ve passed all relevant schema files/class to the parser, call .build() and .makeExecutableSchema() to get a graphql-java GraphQLSchema:\nSchemaParser.newParser() // ... .build() .makeExecutableSchema() If you want to build the GraphQLSchema yourself, you can get all the parsed objects with parseSchemaObjects():\nSchemaParser.newParser() // ... .build() .parseSchemaObjects() GraphQL Descriptions GraphQL object/field/argument descriptions can be provided by comments in the schema:\n# One of the films in the Star Wars Trilogy enum Episode { # Released in 1977 NEWHOPE # Released in 1980 EMPIRE # Released in 1983 JEDI } GraphQL Deprecations GraphQL deprecations on output fields, enums, arguments, directive arguments, and input fields can be provided by the @deprecated(reason: String) directive, and are added to the generated schema. You can either supply a reason argument with a string value or not supply one and receive a \u0026ldquo;No longer supported\u0026rdquo; message when introspected:\n# One of the films in the Star Wars Trilogy enum Episode { # Released in 1977 NEWHOPE, # Released in 1980 EMPIRE, # Released in 1983 JEDI, # Released in 1999 PHANTOM @deprecated(reason: \u0026#34;Not worth referencing\u0026#34;), # Released in 2002 CLONES @deprecated } ","permalink":"https://graphql-java-kickstart.github.io/tools/schema-definition/","tags":null,"title":"Defining a schema"},{"categories":null,"contents":"The GraphQL Servlet library allows you to add a Servlet Listener for listening to the GraphQL request. It provides hooks into the servlet request execution (success, error, and finally):\npublic class MyServlet extends GraphQLHttpServlet { @Override protected GraphQLConfiguration getConfiguration() { return GraphQLConfiguration.with(createSchema()) .with(queryInvoker) .with(Arrays.asList(listener)) .build(); } } Instrumentation The Servlet Listener listens to the servlet request, but not to the GraphQL query execution. If you want to listen to that you should use the Instrumentation provided by GraphQL Java. You can extend SimpleInstrumentation to quickly create a custom implementation and use it when creating the GraphQLConfiguration.\nSee the GraphQL Java documentation for details on creating custom instrumentations.\npublic class MyServlet extends GraphQLHttpServlet { @Override protected GraphQLConfiguration getConfiguration() { GraphQLQueryInvoker queryInvoker = GraphQLQueryInvoker.newBuilder() .withExecutionStrategyProvider(executionStrategyProvider) .with(Arrays.asList(instrumentation)) .build(); return GraphQLConfiguration.with(createSchema()) .with(queryInvoker) .build(); } } ","permalink":"https://graphql-java-kickstart.github.io/servlet/servlet-listener/","tags":null,"title":"Servlet Listener"},{"categories":null,"contents":"For advanced use-cases, the schema parser can be tweaked to suit your needs. Use SchemaParserOptions.newBuilder() to build an options object to pass to the parser.\nOptions:\n contextClass: If you use a custom context object to execute your queries, let the parser know about it so that it can add it to data fetchers as an argument.\nMake sure to also provide your context instance to the execution input:\nvar executionInput = ExecutionInput.newExecutionInput() .query(query) .variables(variables) .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\u0026lt;T\u0026gt;, you must pass Future.class and 0.\n useDefaultGenericWrappers: Defaults to true. Tells the parser whether or not to add it\u0026rsquo;s own list of well-known generic wrappers, such as Future and CompletableFuture.\n 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.\n missingResolverDataFetcher: Allows you to provide custom behavior for missing GraphQL fields.\n 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.\n objectMapperConfigurer / objectMapperProvider: 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.\n preferGraphQLResolver: In cases where you have a Resolver class and legacy class that conflict on type arguments, use the Resolver class instead of throwing an error. Specifically this situation can occur when you have a graphql schema type Foo with a bars property and classes:\n// legacy class you can\u0026#39;t change class Foo { Set\u0026lt;Bar\u0026gt; getBars() { //...returns set of bars... } } // nice resolver that does what you want class FooResolver implements GraphQLResolver\u0026lt;Foo\u0026gt; { Set\u0026lt;BarDTO\u0026gt; getBars() { // ...converts Bar objects to BarDTO objects and returns set... } } You will now have the code find two different return types for getBars() and application will not start with the error Caused by: graphql.kickstart.tools.SchemaClassScannerError: Two different classes used for type If this property is true it will ignore the legacy version.\n addProxyHandler: If your runtime resolver classes are auto-generated proxies of some kind you can provide a handler to help the parser find the real resolvers behind them. Four proxy handlers are provided by default for these libraries:\n Javassist 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.\n fieldVisibility: Provide a graphql field visibility implementation. This option overrides introspectionEnabled when used. See Field Visibility.\n coroutineContext / coroutineContextProvider: Provide a kotlin coroutine context to be used with suspend functions of resolvers.\n typeDefinitionFactory: See Type Definition Factory.\n includeUnusedTypes: Defaults to false. By default, the parser will ignore unused type definitions in the schema. Enable this option to include them regardless.\n ","permalink":"https://graphql-java-kickstart.github.io/tools/schema-parser-options/","tags":null,"title":"Schema parser options"},{"categories":null,"contents":"Relay requires quite some boilerplate type definitions to be defined. They are all the same apart from type of the node the Relay connection targets. This results in schemas with a lot of duplication, like the following:\ntype Query { users(first: Int, after: String): UserConnection organizations(first: Int, after: String): OrganizationConnection } type UserConnection { edges: [UserEdge] pageInfo: PageInfo } type UserEdge { cursor: String node: User } type PageInfo { hasPreviousPage: Boolean! hasNextPage: Boolean! } type User { id: ID! name: String } type OrganizationConnection { edges: [OrganizationEdge] pageInfo: PageInfo } type OrganizationEdge { cursor: String node: Organization } type Organization { id: ID! } Using the Type Definition Factory In version 5.4 of graphql-java-tools the Type Definition Factory has been introduced. This has been added with this particular use case in mind, but can be used for any type of definition that you\u0026rsquo;d want to add dynamically instead of defining it statically in the SDL.\nTo support Relay we have created the RelayConnectionFactory that is enabled by default. It scans the SDL for any fields annotated with the custom directive @connection. For each it will dynamically add the required type definitions to the schema. It also requires the PageInfo type definition.\nBy using this feature the schema definition shown above can be reduced to:\ntype Query { users(first: Int, after: String): UserConnection @connection(for: \u0026#34;User\u0026#34;) organizations(first: Int, after: String): OrganizationConnection @connection(for: \u0026#34;Organization\u0026#34;) } type User { id: ID! name: String } type Organization { id: ID! } The connection type will be created if absent using the type name specified for the field, e.g. UserConnection and OrganizationConnection in the example above. The edge type will get the same name appended with Edge, e.g. UserConnectionEdge and OrganizationConnectionEdge for this example.\nCreating the resolver In the resolvers the Relay connection provided by graphql-java can be used, for example:\nclass QueryResolver implements GraphQLQueryResolver { public Connection\u0026lt;User\u0026gt; users(int first, String after, DataFetchingEnvironment env) { return new SimpleListConnection\u0026lt;\u0026gt;(Collections.singletonList(new User(1L, \u0026#34;Luke\u0026#34;))).get(env); } } ","permalink":"https://graphql-java-kickstart.github.io/tools/relay/","tags":["relay","factory","connection","edge","pageinfo"],"title":"Relay"},{"categories":null,"contents":"The Type Definition Factory has been added with to be able to dynamically add type definitions to the schema instead of having to define them manually in the SDL. There are a couple of use cases where the types that have to be defined are very much alike and only certain parts are different. For example the connection and edge types used by Relay. Since generics isn\u0026rsquo;t supported in the definition language this type definition factory has been added.\nBasic usage Immediately after the SDL has been parsed the schema parser checks if any TypeDefinitionFactory instances have been defined in SchemaParserOptions. By default the RelayConnectionFactory is available.\nYou can add your own type definition factories by implementing the TypeDefinitionFactory. It contains just one method. All definitions that have been found after parsing the SDL and any preceding type definition factories are passed in. This allows you to perform some logic based on the current schema to determine which type definitions to create. You must only return the new type definition you want to add to the schema. The existing definitions that were passed in should not be included in the returned list.\nclass MyTypeDefinitionFactory implements TypeDefinitionFactory { public List\u0026lt;Definition\u0026lt;?\u0026gt;\u0026gt; create(final List\u0026lt;Definition\u0026lt;?\u0026gt;\u0026gt; existing) { return ObjectTypeDefinition.newObjectTypeDefinition() .name(\u0026#34;MyType\u0026#34;) .fieldDefinition(new fieldDefinition(\u0026#34;myField\u0026#34;, new TypeName(\u0026#34;String\u0026#34;))) .build(); } } Make sure to let graphql-spring-boot know you want to use your custom type definition factory by simply exposing it as a bean, e.g.:\n@Bean public TypeDefinitionFactory myTypeDefinitionFactory() { return new MyTypeDefinitionFactory(); } ","permalink":"https://graphql-java-kickstart.github.io/spring-boot/type-definition-factory/","tags":["type","factory","definition","dynamic","relay"],"title":"Type Definition Factory"},{"categories":null,"contents":"The Type Definition Factory has been added to allow to dynamically add type definitions to the schema instead of having to define them manually in the SDL. There are a couple of use cases where the types that have to be defined are very much alike and only certain parts are different. For example the connection and edge types used by Relay. Since generics aren\u0026rsquo;t supported in the definition language this type definition factory has been added.\nBasic usage Immediately after the SDL has been parsed the schema parser checks if any TypeDefinitionFactory instances have been defined in SchemaParserOptions. By default the RelayConnectionFactory is available.\nYou can add your own type definition factories by implementing the TypeDefinitionFactory. It contains just one method. All definitions that have been found after parsing the SDL and any preceding type definition factories are passed in. This allows you to perform some logic based on the current schema to determine which type definitions to create. You must only return the new type definition you want to add to the schema. The existing definitions that were passed in should not be included in the returned list.\nclass MyTypeDefinitionFactory implements TypeDefinitionFactory { public List\u0026lt;Definition\u0026lt;?\u0026gt;\u0026gt; create(final List\u0026lt;Definition\u0026lt;?\u0026gt;\u0026gt; existing) { return ObjectTypeDefinition.newObjectTypeDefinition() .name(\u0026#34;MyType\u0026#34;) .fieldDefinition(new fieldDefinition(\u0026#34;myField\u0026#34;, new TypeName(\u0026#34;String\u0026#34;))) .build(); } } Make sure to let graphql-java-tools know you want to use your custom type definition factory by adding it to your SchemaParserOptions, e.g.:\nSchemaParserOptions options = SchemaParserOptions.newOptions() .TypeDefinitionFactory(new MyTypeDefinitionFactory()) .build(); GraphQLSchema schema = SchemaParser.newParser().file(\u0026#34;schema.graphqls\u0026#34;) .resolvers(new QueryResolver()) .options(options) .build() .makeExecutableSchema(); ","permalink":"https://graphql-java-kickstart.github.io/tools/type-definition-factory/","tags":["type","factory","definition","dynamic","relay"],"title":"Type Definition Factory"},{"categories":null,"contents":"See Schema Directives for a detailed explanation about directives including examples on how to define them in the SDL and to create the required classes.\nTo add your custom SchemaDirectiveWiring to graphql-spring-boot create a bean of type SchemaDirective to have it automatically passed along to the SchemaParser\nSchemaDirective.create(\u0026quot;uppercase\u0026quot;, new UppercaseDirective()) Basic usage Let\u0026rsquo;s say you defined a custom directive to make text uppercase in a resource schema.graphqls:\ndirective @uppercase on FIELD_DEFINITION type Query { hello: String @uppercase } And the actual implementation is the following:\npublic class UppercaseDirective implements SchemaDirectiveWiring { @Override public GraphQLFieldDefinition onField(SchemaDirectiveWiringEnvironment\u0026lt;GraphQLFieldDefinition\u0026gt; env) { GraphQLFieldDefinition field = env.getElement(); DataFetcher dataFetcher = DataFetcherFactories.wrapDataFetcher(field.getDataFetcher(), { dataFetchingEnvironment, value -\u0026gt; if (value == null) { return null } return ((String) value).toUpperCase() }) return field.transform({ builder -\u0026gt; builder.dataFetcher(dataFetcher) }); } } Add our custom directive as a bean:\n@Bean public SchemaDirective myCustomDirective() { return new SchemaDirective(\u0026#34;uppercase\u0026#34;, new UppercaseDirective()); } It will then be automatically picked up and added to the SchemaParser.\nSupported locations Support for directives is currently limited to the following locations:\n OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION ENUM INPUT_OBJECT INPUT_FIELD_DEFINITION Meaning directives for the following locations are currently not yet supported:\n SCALAR ENUM_VALUE ","permalink":"https://graphql-java-kickstart.github.io/spring-boot/directives/","tags":["directives"],"title":"Directives"},{"categories":null,"contents":"See Schema Directives for a detailed explanation about directives including examples on how to define them in the SDL and to create the required classes.\nTo add your custom SchemaDirectiveWiring to graphql-java-tools pass it along when creating the SchemaParser using\nSchemaParser.newParser().directive(\u0026quot;name\u0026quot;, new MySchemaDirectiveWiring()).build() Basic usage Let\u0026rsquo;s say you defined a custom directive to make text uppercase in a resource schema.graphqls:\ndirective @uppercase on FIELD_DEFINITION type Query { hello: String @uppercase } And the actual implementation is the following:\npublic class UppercaseDirective implements SchemaDirectiveWiring { @Override public GraphQLFieldDefinition onField(SchemaDirectiveWiringEnvironment\u0026lt;GraphQLFieldDefinition\u0026gt; env) { GraphQLFieldDefinition field = env.getElement(); GraphQLFieldsContainer parentType = env.getFieldsContainer(); // build a data fetcher that transforms the given value to uppercase DataFetcher originalFetcher = env.getCodeRegistry().getDataFetcher(parentType, field); DataFetcher dataFetcher = DataFetcherFactories.wrapDataFetcher( originalFetcher, ((dataFetchingEnvironment, value) -\u0026gt; { if (value instanceof String) { return ((String) value).toUpperCase(); } return value; })); // now change the field definition to use the new uppercase data fetcher env.getCodeRegistry().dataFetcher(parentType, field, dataFetcher); return field; } } Add our custom directive when creating the schema parser:\nSchemaParser.newParser() .file(\u0026#34;schema.graphqls\u0026#34;) .directive(\u0026#34;uppercase\u0026#34;, new UppercaseDirective()) // ... .build() .makeExecutableSchema(); Supported locations Support for directives is currently limited to the following locations:\n OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION ENUM ENUM_VALUE INPUT_OBJECT INPUT_FIELD_DEFINITION Meaning directives for the following locations are currently not yet supported:\n SCALAR ","permalink":"https://graphql-java-kickstart.github.io/tools/directives/","tags":["directives"],"title":"Directives"},{"categories":null,"contents":"The following GraphQL Embedded Editors are bundled for convenience:\n Altair Configuration Parameters GraphQL Playground Configuration Parameters GraphiQL Configuration Parameters GraphQL Voyager Configuration Parameters Altair Altair becomes accessible at the root /altair if the graphql.altair.enabled property is true.\nNote that GraphQL server must be available at /graphql/\\* context to be discovered by Altair.\nConfiguration Parameters Available Spring Boot configuration parameters (either application.yml or application.properties):\ngraphql: altair: enabled: true mapping: /altair subscriptions: timeout: 30 reconnect: false static: base-path: / page-title: Altair cdn: enabled: false version: 4.0.2 options: endpoint-url: /graphql subscriptions-endpoint: /subscriptions initial-settings: theme: dracula initial-headers: Authorization: \u0026#34;Bearer \u0026lt;your-token\u0026gt;\u0026#34; resources: initial-query: defaultQuery.graphql initial-variables: variables.graphql initial-pre-request-script: pre-request.graphql initial-post-request-script: post-request.graphql GraphQL Playground GraphQL Playground becomes accessible at root /playground (or as configured in graphql.playground.mapping) if the graphql.playground.enabled property is true.\nIt uses an embedded GraphQL Playground React, in accordance to the official guide, using the \u0026lsquo;minimum HTML\u0026rsquo; approach.\nConfiguration Parameters Available Spring Boot configuration parameters (either application.yml or application.properties):\ngraphql: playground: mapping: /playground endpoint: /graphql subscriptionEndpoint: /subscriptions staticPath.base: my-playground-resources-folder enabled: true pageTitle: Playground cdn: enabled: false version: latest settings: editor.cursorShape: line editor.fontFamily: \u0026#34;\u0026#39;Source Code Pro\u0026#39;, \u0026#39;Consolas\u0026#39;, \u0026#39;Inconsolata\u0026#39;, \u0026#39;Droid Sans Mono\u0026#39;, \u0026#39;Monaco\u0026#39;, monospace\u0026#34; editor.fontSize: 14 editor.reuseHeaders: true editor.theme: dark general.betaUpdates: false prettier.printWidth: 80 prettier.tabWidth: 2 prettier.useTabs: false request.credentials: omit schema.polling.enable: true schema.polling.endpointFilter: \u0026#34;*localhost*\u0026#34; schema.polling.interval: 2000 schema.disableComments: true tracing.hideTracingResponse: true headers: headerFor: AllTabs tabs: - name: Example Tab query: classpath:exampleQuery.graphql headers: SomeHeader: Some value variables: classpath:variables.json responses: - classpath:exampleResponse1.json - classpath:exampleResponse2.json GraphiQL GraphiQL becomes accessible at the root /graphiql if graphql.graphiql.enabled application property is set to true.\nNote that GraphQL server must be available at /graphql/* context to be discovered by GraphiQL.\nConfiguration Parameters Available Spring Boot configuration parameters (either application.yml or application.properties):\ngraphql: graphiql: mapping: /graphiql endpoint: graphql: /graphql subscriptions: /subscriptions subscriptions: timeout: 30 reconnect: false basePath: / enabled: true pageTitle: GraphiQL cdn: enabled: false version: latest props: resources: query: query.graphql defaultQuery: defaultQuery.graphql variables: variables.graphql variables: editorTheme: \u0026#34;solarized light\u0026#34; headers: Authorization: \u0026#34;Bearer \u0026lt;your-token\u0026gt;\u0026#34; By default GraphiQL is served from within the package. This can be configured to be served from CDN instead, by setting the property graphiql.cdn.enabled to true.\nYou are able to set the GraphiQL props as well. The graphiql.props.variables group can contain any of the props as defined at GraphiQL Usage. Since setting (large) queries in the properties like this isn\u0026rsquo;t very readable, you can use the properties in the graphiql.props.resources group to set the classpath resources that should be loaded.\nHeaders that are used when sending the GraphiQL queries can be set by defining them in the graphiql.headers group.\nGraphQL Voyager GraphQL Voyager becomes accessible at root /voyager (or as configured in voyager.mapping) if the graphql.voyager.enabled property is true.\nAvailable Spring Boot configuration parameters (either application.yml or application.properties):\nConfiguration Parameters Available Spring Boot configuration parameters (either application.yml or application.properties):\nvoyager: enabled: true basePath: / mapping: /voyager endpoint: /graphql cdn: enabled: false version: latest pageTitle: Voyager displayOptions: skipRelay: true skipDeprecated: true rootType: Query sortByAlphabet: false showLeafFields: true hideRoot: false hideDocs: false hideSettings: false ","permalink":"https://graphql-java-kickstart.github.io/spring-boot/embedded-editors/","tags":["tooling","embedded","editors","altair","graphiql","voyager","playground"],"title":"Embedded Editors"},{"categories":null,"contents":"The OsgiGraphQLHttpServlet uses a \u0026ldquo;provider\u0026rdquo; model to supply the servlet with the required objects:\n GraphQLQueryProvider: Provides query fields to the GraphQL schema. GraphQLMutationProvider: Provides mutation fields to the GraphQL schema. GraphQLTypesProvider: Provides type information to the GraphQL schema. ExecutionStrategyProvider: Provides an execution strategy for running each query. GraphQLContextBuilder: Builds a context for running each query. Examples You can now find some example on how to use graphql-java-servlet.\nRequirements The OSGi examples use Maven as a build tool because it requires plugins that are not (yet) available for Gradle. Therefore you will need Maven 3.2+.\nBuilding \u0026amp; running the OSGi examples You can build the OSGi examples sub-projects by simply executing the following command from the examples/osgi directory:\nmvn clean install This will generate a complete Apache Karaf distribution in the following files:\n examples/osgi/apache-karaf-package/target/graphql-java-servlet-osgi-examples-apache-karaf-package-VERSION.tar.gz(.zip) You can simply uncompress this file and launch the OSGi server using the command from the uncompressed directory:\nbin/karaf You should then be able to access the GraphQL endpoint at the following URL once the server is started:\nhttp://localhost:8181/graphql/schema.json If you see the JSON result of an introspection query, then all is ok. If not, check the data/log/karaf.log file for any errors.\nWe also provide a script file to do all of the building and running at once (only for Linux / MacOS):\n./buildAndRun.sh Deploying inside Apache Karaf server You can use the graphql-java-servlet as part of an Apache Karaf feature, as you can see in the example project here:\n pom.xml And here is a sample src/main/feature/feature.xml file to add some dependencies on other features:\n feature.xml Example GraphQL provider implementation Here\u0026rsquo;s an example of a GraphQL provider that implements three interfaces at the same time.\n ExampleGraphQLProvider Relay.js support Relay.js support is provided by the EnhancedExecutionStrategy of graphql-java-annotations. You MUST pass this execution strategy to the servlet for Relay.js support.\nThis is the default execution strategy for the OsgiGraphQLHttpServlet, and must be added as a dependency when using that servlet.\n","permalink":"https://graphql-java-kickstart.github.io/servlet/osgi/","tags":null,"title":"OSGi"}]