### Install graphql-java Locally Source: https://www.graphql-java.com/documentation/contributions Use this command to install the built project into your local Maven repository. ```bash ./gradlew install ``` -------------------------------- ### Basic Hello World Example with graphql-java Source: https://www.graphql-java.com/documentation/getting-started A simple 'Hello World' example demonstrating how to define a schema, wire data fetchers, build an executable schema, and execute a query using graphql-java. ```java import graphql.ExecutionResult; import graphql.GraphQL; import graphql.schema.GraphQLSchema; import graphql.schema.StaticDataFetcher; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import static graphql.schema.idl.RuntimeWiring.newRuntimeWiring; public class HelloWorld { public static void main(String[] args) { String schema = "type Query{hello: String}"; SchemaParser schemaParser = new SchemaParser(); TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema); RuntimeWiring runtimeWiring = newRuntimeWiring() .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world"))) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring); GraphQL build = GraphQL.newGraphQL(graphQLSchema).build(); ExecutionResult executionResult = build.execute("{hello}"); System.out.println(executionResult.getData().toString()); // Prints: {hello=world} } } ``` -------------------------------- ### GraphQL Query Example Source: https://www.graphql-java.com/documentation/data-mapping An example of a GraphQL query to fetch product information, including specific fields like id, name, cost, and tax. ```graphql query ProductQuery { products(match : "Paper*") { id, name, cost, tax } } ``` -------------------------------- ### GraphQL Query Example Source: https://www.graphql-java.com/documentation/data-fetching This is an example GraphQL query demonstrating a selection set for the 'products' field. It shows how sub-fields like 'name', 'description', and nested 'sellingLocations' represent the requested data. ```graphql query { products { name description sellingLocations { state } } } ``` -------------------------------- ### GraphQL Subscription Query Example Source: https://www.graphql-java.com/documentation/schema A basic example of a GraphQL subscription query. Subscriptions allow receiving real-time updates when backing objects change. ```graphql subscription foo { # normal graphql query } ``` -------------------------------- ### GraphQL Mutation Query Example Source: https://www.graphql-java.com/documentation/execution This is an example of how a mutation is invoked via a query, including variables for input arguments. ```graphql mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } } ``` -------------------------------- ### GraphQL Subscription Query Example Source: https://www.graphql-java.com/documentation/subscriptions This is an example of a GraphQL subscription query to fetch stock quote data for a specific stock code. ```graphql subscription StockCodeSubscription { stockQuotes(stockCode:"IBM") { dateTime stockCode stockPrice stockPriceChange } } ``` -------------------------------- ### Product DTO with Formatted Launch Date Source: https://www.graphql-java.com/documentation/data-fetching Example of a DTO that uses the DataFetchingEnvironment to format the launch date based on a provided dateFormat argument. ```java class ProductDTO { private ID id; private String name; private String description; private Double cost; private Double tax; private LocalDateTime launchDate; // ... public String getName() { return name; } // ... public String getLaunchDate(DataFetchingEnvironment environment) { String dateFormat = environment.getArgument("dateFormat"); return yodaTimeFormatter(launchDate,dateFormat); } } ``` -------------------------------- ### Example GraphQL Query Source: https://www.graphql-java.com/documentation/field-selection A sample GraphQL query demonstrating field selection for a 'user' object and its nested 'friends'. ```graphql query { user(userId : "xyz") { name age weight friends { name } } } ``` -------------------------------- ### GraphQL Subscription Execution and Stream Handling Source: https://www.graphql-java.com/documentation/subscriptions Execute a subscription query and obtain a reactive streams `Publisher` to process incoming data. This example demonstrates setting up the GraphQL instance, defining the query, executing it, and retrieving the data stream. ```java GraphQL graphQL = GraphQL .newGraphQL(schema) .subscriptionExecutionStrategy(new SubscriptionExecutionStrategy()) .build(); String query = "" + " subscription StockCodeSubscription {\n" + " stockQuotes(stockCode:\"IBM\") {\n" + " dateTime\n" + " stockCode\n" + " stockPrice\n" + " stockPriceChange\n" + " }\n" + " }\n"; ExecutionResult executionResult = graphQL.execute(query); Publisher stockPriceStream = executionResult.getData(); AtomicReference subscriptionRef = new AtomicReference<>(); stockPriceStream.subscribe(new Subscriber() { @Override public void onSubscribe(Subscription s) { subscriptionRef.set(s); s.request(1); } @Override public void onNext(ExecutionResult er) { // // process the next stock price // processStockPriceChange(er.getData()); // // ask the publisher for one more item please // subscriptionRef.get().request(1); } @Override public void onError(Throwable t) { // // The upstream publishing data source has encountered an error // and the subscription is now terminated. Real production code needs // to decide on a error handling strategy. // } @Override public void onComplete() { // // the subscription has completed. There is not more data // } }); ``` -------------------------------- ### Relay Connection Field Selection Example Source: https://www.graphql-java.com/documentation/field-selection A GraphQL query for fetching users with Relay connections, demonstrating nested field selection. ```graphql query { users(first:10) { edges { node { name age weight friends { name } } } } } ``` -------------------------------- ### Chained DataLoader Example Source: https://www.graphql-java.com/documentation/batching Demonstrates a DataFetcher where one DataLoader depends on the result of another. This chaining is automatically handled in GraphQL Java 25.0+. ```java DataFetcher> df1 = env -> { return env.getDataLoader("name").load("Key1").thenCompose(result -> { return env.getDataLoader("email").load(result); }); }; ``` -------------------------------- ### Implement Query Caching with PreparsedDocumentProvider Source: https://www.graphql-java.com/documentation/execution This example demonstrates how to set up query caching using Caffeine and PreparsedDocumentProvider. It caches parsed `Document` instances to avoid re-parsing and validation. Ensure the cache is thread-safe and shared. For a high cache hit ratio, pass field arguments as variables. ```java Cache cache = Caffeine.newBuilder().maximumSize(10_000).build(); (1) PreparsedDocumentProvider preparsedCache = new PreparsedDocumentProvider() { @Override public CompletableFuture getDocumentAsync(ExecutionInput executionInput, Function computeFunction) { Function mapCompute = key -> computeFunction.apply(executionInput); return CompletableFuture.completedFuture(cache.get(executionInput.getQuery(), mapCompute)); } }; GraphQL graphQL = GraphQL.newGraphQL(StarWarsSchema.starWarsSchema) .preparsedDocumentProvider(preparsedCache) (2) .build(); ``` ```graphql query HelloTo { sayHello(to: "Me") { greeting } } ``` ```graphql query HelloTo($to: String!) { sayHello(to: $to) { greeting } } ``` ```json { "to": "Me" } ``` -------------------------------- ### Example Deep Query Source: https://www.graphql-java.com/documentation/instrumentation This query demonstrates a nested structure that could exceed a defined depth limit. ```graphql query { hero { name friends { name friends { name friends { name } } } } } ``` -------------------------------- ### Star Wars GraphQL Query Example Source: https://www.graphql-java.com/documentation/batching A sample GraphQL query demonstrating a nested data structure for fetching a hero and their friends' friends. This query can lead to inefficient data loading without batching. ```graphql { hero { name friends { name friends { name } } } } ``` -------------------------------- ### Delayed DataLoader Example Source: https://www.graphql-java.com/documentation/batching Illustrates a 'delayed' DataLoader where the DataLoader depends on a slow asynchronous task. When chaining is enabled, these are enqueued for dispatch after the async task completes. ```groovy def fooDF = { env -> return supplyAsync { Thread.sleep(1000) return "fooFirstValue" }.thenCompose { return env.getDataLoader("dl").load(it) } } as DataFetcher def barDF = { env -> return supplyAsync { Thread.sleep(1000) return "barFirstValue" }.thenCompose { return env.getDataLoader("dl").load(it) } } as DataFetcher ``` -------------------------------- ### Custom DataFetcher Implementation Source: https://www.graphql-java.com/documentation/execution Implement a custom DataFetcher to retrieve data, potentially involving database calls or external HTTP requests. This example fetches a user by ID. ```java DataFetcher userDataFetcher = new DataFetcher() { @Override public Object get(DataFetchingEnvironment environment) { return fetchUserFromDatabase(environment.getArgument("userId")); } }; ``` -------------------------------- ### GraphQL Interface Definition (SDL) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Interface using Schema Definition Language (SDL). Interfaces define a set of fields that types can implement. ```graphql interface ComicCharacter { name: String } ``` -------------------------------- ### GraphQL Object Type Definition (SDL) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Object type using Schema Definition Language (SDL). This defines the structure and fields of an object. ```graphql type SimpsonCharacter { name: String mainCharacter: Boolean } ``` -------------------------------- ### GraphQL Input Object Definition (SDL) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Input Object type using Schema Definition Language (SDL). Input objects are used for arguments to fields or as input to mutations. ```graphql input Character { name: String } ``` -------------------------------- ### Asynchronous DataFetcher Returning CompletableFuture Source: https://www.graphql-java.com/documentation/execution A DataFetcher can return a CompletableFuture, enabling parallel fetching of data. This example uses ForkJoinPool.commonPool() for asynchronous operations. ```java DataFetcher userDataFetcher = new DataFetcher() { @Override public Object get(DataFetchingEnvironment environment) { CompletableFuture userPromise = CompletableFuture.supplyAsync(() -> { return fetchUserViaHttp(environment.getArgument("userId")); }); return userPromise; } }; ``` -------------------------------- ### GraphQL Interface Definition (Java) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Interface programmatically using the graphql-java library. This defines an abstract comic character interface. ```java GraphQLInterfaceType comicCharacter = newInterface() .name("ComicCharacter") .description("An abstract comic character.") .field(newFieldDefinition() .name("name") .description("The name of the character.") .type(GraphQLString)) .build(); ``` -------------------------------- ### Cross-Request Caching with Redis DataLoader Source: https://www.graphql-java.com/documentation/batching Demonstrates how to configure a DataLoader to use a custom ValueCache implementation that interacts with Redis for cross-request data sharing. This setup ensures data loaders are still created per request but leverage an external cache. ```java ValueCache crossRequestValueCache = new ValueCache() { @Override public CompletableFuture get(String key) { return redisIntegration.getValue(key); } @Override public CompletableFuture set(String key, Object value) { return redisIntegration.setValue(key, value); } @Override public CompletableFuture delete(String key) { return redisIntegration.clearKey(key); } @Override public CompletableFuture clear() { return redisIntegration.clearAll(); } }; DataLoaderOptions options = DataLoaderOptions.newOptions().setValueCache(crossRequestValueCache); DataLoader dataLoader = DataLoaderFactory.newDataLoader(batchLoader, options); ``` -------------------------------- ### Java Email Scalar Implementation Source: https://www.graphql-java.com/documentation/scalars Implement a custom GraphQL scalar for email addresses. This example shows how to define the scalar and its coercing methods for serialization and parsing. ```java public static class EmailScalar { public static final GraphQLScalarType EMAIL = GraphQLScalarType.newScalar() .name("email") .description("A custom scalar that handles emails") .coercing(new Coercing() { @Override public Object serialize(Object dataFetcherResult, GraphQLContext graphQLContext, Locale locale) { return serializeEmail(dataFetcherResult); } @Override public Object parseValue(Object input, GraphQLContext graphQLContext, Locale locale) { return parseEmailFromVariable(input); } @Override public Object parseLiteral(Value input, CoercedVariables variables, GraphQLContext graphQLContext, Locale locale) { return parseEmailFromAstLiteral(input); } }) .build(); private static boolean looksLikeAnEmailAddress(String possibleEmailValue) { // ps. I am not trying to replicate RFC-3696 clearly return Pattern.matches("[A-Za-z0-9]@[.*]", possibleEmailValue); } private static Object serializeEmail(Object dataFetcherResult) { String possibleEmailValue = String.valueOf(dataFetcherResult); if (looksLikeAnEmailAddress(possibleEmailValue)) { return possibleEmailValue; } else { throw new CoercingSerializeException("Unable to serialize " + possibleEmailValue + " as an email address"); } } private static Object parseEmailFromVariable(Object input) { if (input instanceof String) { String possibleEmailValue = input.toString(); if (looksLikeAnEmailAddress(possibleEmailValue)) { return possibleEmailValue; } } throw new CoercingParseValueException("Unable to parse variable value " + input + " as an email address"); } private static Object parseEmailFromAstLiteral(Object input) { if (input instanceof StringValue) { String possibleEmailValue = ((StringValue) input).getValue(); if (looksLikeAnEmailAddress(possibleEmailValue)) { return possibleEmailValue; } } throw new CoercingParseLiteralException( "Value is not any email address : '" + String.valueOf(input) + "'"); } } ``` -------------------------------- ### GraphQL Input Object Definition (Java) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Input Object type programmatically using the graphql-java library. This defines an input object with a string field. ```java GraphQLInputObjectType inputObjectType = newInputObject() .name("inputObjectType") .field(newInputObjectField() .name("field") .type(GraphQLString)) .build(); ``` -------------------------------- ### GraphQL Non-Null Input Type Example Source: https://www.graphql-java.com/documentation/data-mapping Illustrates a GraphQL query field with a non-null String argument. The 'arg1' field argument will always be a non-null java.lang.String value at runtime. ```graphql type Query { field(arg1 : String!, arg2 : String) : String } ``` -------------------------------- ### Build graphql-java Project Source: https://www.graphql-java.com/documentation/contributions Run this command to build the project. The resulting jar file will be in the `build/libs` directory. ```bash ./gradlew build ``` -------------------------------- ### Run Tests for graphql-java Source: https://www.graphql-java.com/documentation/contributions Execute this command to run all the project's tests. All tests are written in Spock. ```bash ./gradlew test ``` -------------------------------- ### Configure GraphQL for Subscriptions Source: https://www.graphql-java.com/documentation/subscriptions Set up the GraphQL instance to use `SubscriptionExecutionStrategy` for handling reactive streams in subscriptions. ```java GraphQL graphQL = GraphQL .newGraphQL(schema) .subscriptionExecutionStrategy(new SubscriptionExecutionStrategy()) .build(); ExecutionResult executionResult = graphQL.execute(query); Publisher stockPriceStream = executionResult.getData(); ``` -------------------------------- ### Mapping Data Together Using a List of Maps Source: https://www.graphql-java.com/documentation/data-mapping Demonstrates how to combine product information, cost, and tax data into a unified view using a List of Maps. ```java private List mapDataTogetherViaMap(List productInfo, List productCostInfo, List productTaxInfo) { List unifiedView = new ArrayList<>(); for (int i = 0; i < productInfo.size(); i++) { ProductInfo info = productInfo.get(i); ProductCostInfo cost = productCostInfo.get(i); ProductTaxInfo tax = productTaxInfo.get(i); Map objectMap = new HashMap<>(); objectMap.put("id", info.getId()); objectMap.put("name", info.getName()); objectMap.put("description", info.getDescription()); objectMap.put("cost", cost.getCost()); objectMap.put("tax", tax.getTax()); unifiedView.add(objectMap); } return unifiedView; } ``` -------------------------------- ### Build Runtime Wiring for Executable Schema Source: https://www.graphql-java.com/documentation/schema This code demonstrates how to build the runtime wiring for a schema, associating data fetchers and type resolvers with schema types and fields. ```java RuntimeWiring buildRuntimeWiring() { return RuntimeWiring.newRuntimeWiring() .scalar(CustomScalar) // this uses builder function lambda syntax .type("QueryType", typeWiring -> typeWiring .dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo())) .dataFetcher("human", StarWarsData.getHumanDataFetcher()) .dataFetcher("droid", StarWarsData.getDroidDataFetcher())) .type("Human", typeWiring -> typeWiring .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())) // you can use builder syntax if you don't like the lambda syntax .type("Droid", typeWiring -> typeWiring .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())) // or full builder syntax if that takes your fancy .type( newTypeWiring("Character") .typeResolver(StarWarsData.getCharacterTypeResolver()) .build()) .build(); } ``` -------------------------------- ### Create Subscription Publisher DataFetcher Source: https://www.graphql-java.com/documentation/subscriptions Implement a `DataFetcher` to return a `Publisher` for subscription data. This fetcher retrieves arguments from the environment and uses them to build the appropriate publisher. ```java DataFetcher> publisherDataFetcher = new DataFetcher>() { @Override public Publisher get(DataFetchingEnvironment environment) { String stockCodeArg = environment.getArgument("stockCode"); return buildPublisherForStockCode(stockCodeArg); } }; ``` -------------------------------- ### Build Executable Schema with Directive Source: https://www.graphql-java.com/documentation/directives Constructs the executable GraphQL schema by parsing the SDL, defining the directive wiring, and generating the schema. ```java static GraphQLSchema buildSchema() { String sdlSpec = "directive @dateFormat on FIELD_DEFINITION\n" + "type Query {\n" + " dateField : String @dateFormat \n" + "}"; TypeDefinitionRegistry registry = new SchemaParser().parse(sdlSpec); RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() .directive("dateFormat", new DateFormatting()) .build(); return new SchemaGenerator().makeExecutableSchema(registry, runtimeWiring); } ``` -------------------------------- ### GraphQL Enum Definition (SDL) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Enum type using Schema Definition Language (SDL). Enums represent a set of predefined values. ```graphql enum Color { RED GREEN BLUE } ``` -------------------------------- ### GraphQL Object Type Definition (Java) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Object type programmatically using the graphql-java library. This mirrors the SDL definition for a Simpson character. ```java GraphQLObjectType simpsonCharacter = newObject() .name("SimpsonCharacter") .description("A Simpson character") .field(newFieldDefinition() .name("name") .description("The name of the character.") .type(GraphQLString)) .field(newFieldDefinition() .name("mainCharacter") .description("One of the main Simpson characters?") .type(GraphQLBoolean)) .build(); ``` -------------------------------- ### Build Dynamic Runtime Wiring with WiringFactory Source: https://www.graphql-java.com/documentation/schema Implement a WiringFactory to dynamically wire TypeResolvers and DataFetchers based on SDL definitions like directives. This allows for more flexible runtime configuration. ```java RuntimeWiring buildDynamicRuntimeWiring() { WiringFactory dynamicWiringFactory = new WiringFactory() { @Override public boolean providesTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) { return getDirective(definition,"specialMarker") != null; } @Override public boolean providesTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) { return getDirective(definition,"specialMarker") != null; } @Override public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) { Directive directive = getDirective(definition,"specialMarker"); return createTypeResolver(definition,directive); } @Override public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) { Directive directive = getDirective(definition,"specialMarker"); return createTypeResolver(definition,directive); } @Override public boolean providesDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) { return getDirective(definition,"dataFetcher") != null; } @Override public DataFetcher getDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) { Directive directive = getDirective(definition, "dataFetcher"); return createDataFetcher(definition,directive); } }; return RuntimeWiring.newRuntimeWiring() .wiringFactory(dynamicWiringFactory).build(); } ``` -------------------------------- ### GraphQL Enum Definition (Java) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Enum type programmatically using the graphql-java library. This defines an enum for colors with RED, GREEN, and BLUE values. ```java GraphQLEnumType colorEnum = newEnum() .name("Color") .description("Supported colors.") .value("RED") .value("GREEN") .value("BLUE") .build(); ``` -------------------------------- ### GraphQL Schema Transformation Commands Source: https://www.graphql-java.com/documentation/schema Illustrates the different command methods available within a GraphQLTypeVisitorStub to instruct SchemaTransformer on how to modify the schema DAG. These commands include changing, inserting, deleting, or continuing without modification. ```java GraphQLTypeVisitorStub visitor = new GraphQLTypeVisitorStub() { @Override public TraversalControl visitGraphQLObjectType(GraphQLObjectType objectType, TraverserContext context) { // changes the current element in the schema return changeNode(context, updatedElement); // inserts a new element after the current one in the schema return insertAfter(context, newElement); // inserts a new element before the current one in teh schema return insertBefore(context, newElement); // deletes the current element from the schema return deleteNode(context); // just continue with no change return CONTINUE; } }; ``` -------------------------------- ### Custom DataFetcher for Products Source: https://www.graphql-java.com/documentation/data-fetching Implement a custom DataFetcher to retrieve product data, potentially from a database, with filtering capabilities. ```java DataFetcher productsDataFetcher = new DataFetcher>() { @Override public List get(DataFetchingEnvironment environment) { DatabaseSecurityCtx ctx = environment.getGraphQlContext().get("databaseSecurityCtx"); List products; String match = environment.getArgument("match"); if (match != null) { products = fetchProductsFromDatabaseWithMatching(ctx, match); } else { products = fetchAllProductsFromDatabase(ctx); } return products; } }; ``` -------------------------------- ### GraphQL Java DataFetcher for Operation Directives Source: https://www.graphql-java.com/documentation/directives Example of a GraphQL Java DataFetcher that accesses and processes operation directives, specifically the `@cache` directive and its `maxAge` argument, during query execution. ```java DataFetcher cacheDataFetcher = new DataFetcher() { @Override public Object get(DataFetchingEnvironment env) { QueryDirectives queryDirectives = env.getQueryDirectives(); List cacheDirectives = queryDirectives .getImmediateAppliedDirective("cache"); // We get a List, because we could have // repeatable directives if (cacheDirectives.size() > 0) { QueryAppliedDirective cache = cacheDirectives.get(0); QueryAppliedDirectiveArgument maxAgeArgument = cache.getArgument("maxAge"); int maxAge = maxAgeArgument.getValue(); // Now we know the max allowed cache time and // can make use of it // Your logic goes here } } }; ``` -------------------------------- ### Programmatic Schema Creation with DataFetcher Source: https://www.graphql-java.com/documentation/schema Demonstrates how to create a GraphQL schema programmatically by defining a DataFetcher and an Object type. The DataFetcher is responsible for fetching data for a specific field. ```java DataFetcher fooDataFetcher = new DataFetcher() { @Override public Foo get(DataFetchingEnvironment environment) { // environment.getSource() is the value of the surrounding // object. In this case described by objectType Foo value = perhapsFromDatabase(); // Perhaps getting from a DB or whatever return value; } }; GraphQLObjectType objectType = newObject() .name("ObjectType") .field(newFieldDefinition() .name("foo") .type(GraphQLString) ) .build(); GraphQLCodeRegistry codeRegistry = newCodeRegistry() .dataFetcher( coordinates("ObjectType", "foo"), fooDataFetcher) .build(); ``` -------------------------------- ### Implement BatchLoaderWithContext in Java Source: https://www.graphql-java.com/documentation/batching Implement the BatchLoaderWithContext interface to define how data is loaded in batches, accessing both overall and per-key context objects provided by the BatchLoaderEnvironment. ```java BatchLoaderWithContext batchLoaderWithCtx = new BatchLoaderWithContext() { @Override public CompletionStage> load(List keys, BatchLoaderEnvironment loaderContext) { // // we can have an overall context object SecurityContext securityCtx = loaderContext.getContext(); // // and we can have a per key set of context objects Map keysToSourceObjects = loaderContext.getKeyContexts(); return CompletableFuture.supplyAsync(() -> getTheseCharacters(securityCtx.getToken(), keys, keysToSourceObjects)); } }; // .... SecurityContext securityCtx = SecurityContext.newSecurityContext(); BatchLoaderContextProvider contextProvider = new BatchLoaderContextProvider() { @Override public Object getContext() { return securityCtx; } }; // // this creates an overall context for the dataloader // DataLoaderOptions loaderOptions = DataLoaderOptions.newOptions().setBatchLoaderContextProvider(contextProvider); DataLoader characterDataLoader = DataLoaderFactory.newDataLoader(batchLoaderWithCtx, loaderOptions); // .... DataFetcher dataFetcherThatCallsTheDataLoader = new DataFetcher() { @Override public Object get(DataFetchingEnvironment environment) { String argId = environment.getArgument("id"); Object source = environment.getSource(); // // you can pass per load call contexts // return characterDataLoader.load(argId, source); } }; ``` -------------------------------- ### GraphQL Union Definition and TypeResolver (Java) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Union type and its associated TypeResolver programmatically using graphql-java. The TypeResolver determines which concrete type to return for the union. ```java TypeResolver typeResolver = new TypeResolver() { @Override public GraphQLObjectType getType(TypeResolutionEnvironment env) { if (env.getObject() instanceof Cat) { return CatType; } if (env.getObject() instanceof Dog) { return DogType; } return null; } }; GraphQLUnionType PetType = newUnionType() .name("Pet") .possibleType(CatType) .possibleType(DogType) .build(); GraphQLCodeRegistry codeRegistry = newCodeRegistry() .typeResolver("Pet", typeResolver) .build(); ``` -------------------------------- ### Using AsyncDataFetcher Shortcut Source: https://www.graphql-java.com/documentation/execution Utilize the graphql.schema.AsyncDataFetcher.async() helper to wrap DataFetchers for asynchronous execution, improving code readability with static imports. ```java DataFetcher userDataFetcher = async(environment -> fetchUserViaHttp(environment.getArgument("userId"))); ``` -------------------------------- ### GraphQL Union Definition (SDL) Source: https://www.graphql-java.com/documentation/schema Example of defining a GraphQL Union type using Schema Definition Language (SDL). Unions represent a type that could be one of several possible object types. ```graphql type Cat { name: String lives: Int } type Dog { name: String bonesOwned: Int } union Pet = Cat | Dog ``` -------------------------------- ### Basic Custom Instrumentation Implementation Source: https://www.graphql-java.com/documentation/instrumentation Implement a custom instrumentation to measure overall execution time. This involves creating a state object and overriding methods like beginExecution. ```java class CustomInstrumentation extends SimplePerformantInstrumentation { @Override public InstrumentationState createState() { // instrumentation state is passed during each invocation of an Instrumentation method // and allows you to put stateful data away and reference it during the query execution return new CustomInstrumentationState(); } @Override public @Nullable InstrumentationContext beginExecution(InstrumentationExecutionParameters parameters, InstrumentationState state) { long startNanos = System.nanoTime(); return new SimpleInstrumentationContext() { @Override public void onCompleted(ExecutionResult result, Throwable t) { ((CustomInstrumentationState) state).recordTiming(parameters.getQuery(), System.nanoTime() - startNanos); } }; } @Override public @NotNull DataFetcher instrumentDataFetcher(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, InstrumentationState state) { // this allows you to intercept the data fetcher used to fetch a field and provide another one, perhaps // that enforces certain behaviours or has certain side effects on the data return dataFetcher; } @Override public @NotNull CompletableFuture instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters, InstrumentationState state) { // this allows you to instrument the execution result somehow. For example the Tracing support uses this to put // the `extensions` map of data in place return CompletableFuture.completedFuture(executionResult); } } ``` -------------------------------- ### Provide Authorization Context to Execution Input Source: https://www.graphql-java.com/documentation/directives Shows how to include a custom authorization context in the `ExecutionInput` to be accessible during data fetching. ```java AuthorisationCtx authCtx = AuthorisationCtx.obtain(); ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(query) .graphQLContext(builder -> builder.put("authContext", authCtx)) .build(); ``` -------------------------------- ### Configuring Query and Mutation Execution Strategies Source: https://www.graphql-java.com/documentation/execution Use this to set custom execution strategies for queries and mutations when building the GraphQL object. The AsyncExecutionStrategy and AsyncSerialExecutionStrategy are common choices for performance. ```java GraphQL.newGraphQL(schema) .queryExecutionStrategy(new AsyncExecutionStrategy()) .mutationExecutionStrategy(new AsyncSerialExecutionStrategy()) .build(); ``` -------------------------------- ### Star Wars GraphQL Query Result Example Source: https://www.graphql-java.com/documentation/batching The JSON result of the Star Wars GraphQL query, illustrating a common graph of data where entities share many friends. This structure highlights the need for efficient data fetching. ```json { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker", "friends": [ {"name": "Han Solo"}, {"name": "Leia Organa"}, {"name": "C-3PO"}, {"name": "R2-D2"} ] }, { "name": "Han Solo", "friends": [ {"name": "Luke Skywalker"}, {"name": "Leia Organa"}, {"name": "R2-D2"} ] }, { "name": "Leia Organa", "friends": [ {"name": "Luke Skywalker"}, {"name": "Han Solo"}, {"name": "C-3PO"}, {"name": "R2-D2"} ] } ] } } ``` -------------------------------- ### Enable Chained DataLoaders Configuration Source: https://www.graphql-java.com/documentation/batching Shows how to opt-in to the Chained DataLoaders feature by setting `enableDataLoaderChaining(true)` in `GraphQLUnusualConfiguration.DataloaderConfig`. ```java GraphQL graphQL = GraphQL.unusualConfiguration(graphqlContext) .dataloaderConfig() .enableDataLoaderChaining(true); ``` -------------------------------- ### Add graphql-java Development Build with Maven Source: https://www.graphql-java.com/documentation/getting-started Integrate the latest development build of graphql-java into your Maven project by using the version placeholder in your pom.xml. ```xml com.graphql-java graphql-java INSERT_LATEST_VERSION_HERE ``` -------------------------------- ### Execute GraphQL Query Source: https://www.graphql-java.com/documentation/execution Build a GraphQL schema and execute a query against it. The result contains data and/or errors. ```java GraphQLSchema schema = GraphQLSchema.newSchema() .query(queryType) .build(); GraphQL graphQL = GraphQL.newGraphQL(schema) .build(); ExecutionInput executionInput = ExecutionInput.newExecutionInput().query("query { hero { name } }") .build(); ExecutionResult executionResult = graphQL.execute(executionInput); Object data = executionResult.getData(); List errors = executionResult.getErrors(); ``` -------------------------------- ### Generate Executable GraphQL Schema Source: https://www.graphql-java.com/documentation/schema This code shows how to combine a parsed schema definition with runtime wiring to generate a fully executable GraphQL schema. ```java SchemaParser schemaParser = new SchemaParser(); SchemaGenerator schemaGenerator = new SchemaGenerator(); File schemaFile = loadSchema("starWarsSchema.graphqls"); TypeDefinitionRegistry typeRegistry = schemaParser.parse(schemaFile); RuntimeWiring wiring = buildRuntimeWiring(); GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring); ``` -------------------------------- ### Transforming GraphQL Schema with Visitor Source: https://www.graphql-java.com/documentation/schema Demonstrates transforming a GraphQL schema by adding a new field to an object type and defining its data fetcher. Requires implementing a custom GraphQLTypeVisitorStub. ```java GraphQLTypeVisitorStub visitor = new GraphQLTypeVisitorStub() { @Override public TraversalControl visitGraphQLObjectType(GraphQLObjectType objectType, TraverserContext context) { GraphQLCodeRegistry.Builder codeRegistry = context.getVarFromParents(GraphQLCodeRegistry.Builder.class); // we need to change __XXX introspection types to have directive extensions if (someConditionalLogic(objectType)) { GraphQLObjectType newObjectType = buildChangedObjectType(objectType, codeRegistry); return changeNode(context, newObjectType); } return CONTINUE; } private boolean someConditionalLogic(GraphQLObjectType objectType) { // up to you to decide what causes a change, perhaps a directive is on the element return objectType.hasDirective("specialDirective"); } private GraphQLObjectType buildChangedObjectType(GraphQLObjectType objectType, GraphQLCodeRegistry.Builder codeRegistry) { GraphQLFieldDefinition newField = GraphQLFieldDefinition.newFieldDefinition() .name("newField").type(Scalars.GraphQLString).build(); GraphQLObjectType newObjectType = objectType.transform(builder -> builder.field(newField)); DataFetcher newDataFetcher = dataFetchingEnvironment -> { return "someValueForTheNewField"; }; FieldCoordinates coordinates = FieldCoordinates.coordinates(objectType.getName(), newField.getName()); codeRegistry.dataFetcher(coordinates, newDataFetcher); return newObjectType; } }; GraphQLSchema newSchema = SchemaTransformer.transformSchema(schema, visitor); ``` -------------------------------- ### Build GraphQL with TracingInstrumentation Source: https://www.graphql-java.com/documentation/instrumentation Specify a TracingInstrumentation when building the GraphQL object to enable tracing capabilities. ```java GraphQL.newGraphQL(schema) .instrumentation(new TracingInstrumentation()) .build(); ``` -------------------------------- ### GraphQL Object Construction with Instrumentation Source: https://www.graphql-java.com/documentation/batching Builds the `GraphQL` object, applying the configured `DataLoaderDispatcherInstrumentation`. This ensures that data loaders are invoked correctly during query execution. ```java // // now build your graphql object and execute queries on it. // the data loader will be invoked via the data fetchers on the // schema fields // GraphQL graphQL = GraphQL.newGraphQL(buildSchema()) .instrumentation(dispatcherInstrumentation) .build(); ``` -------------------------------- ### Creating a DataLoader Instance Source: https://www.graphql-java.com/documentation/batching Instantiates a `DataLoader` for characters, associating it with the previously defined `characterBatchLoader`. Data loaders are stateful and typically created per execution request. ```java // // a data loader for characters that points to the character batch loader // // Since data loaders are stateful, they are created per execution request. // DataLoader characterDataLoader = DataLoaderFactory.newDataLoader(characterBatchLoader); ``` -------------------------------- ### DataFetcher for Query.products Field Source: https://www.graphql-java.com/documentation/data-mapping Implements a DataFetcher for the Query.products field to retrieve and combine product data from multiple sources. ```java DataFetcher productsDataFetcher = new DataFetcher() { @Override public Object get(DataFetchingEnvironment env) { String matchArg = env.getArgument("match"); List productInfo = getMatchingProducts(matchArg); List productCostInfo = getProductCosts(productInfo); List productTaxInfo = getProductTax(productInfo); return mapDataTogether(productInfo, productCostInfo, productTaxInfo); } }; ``` -------------------------------- ### Asynchronous DataFetcher with Java 8 Lambdas Source: https://www.graphql-java.com/documentation/execution A more concise way to write an asynchronous DataFetcher using Java 8 lambda expressions. ```java DataFetcher userDataFetcher = environment -> CompletableFuture.supplyAsync( () -> fetchUserViaHttp(environment.getArgument("userId"))); ``` -------------------------------- ### Enable GraphQL Request Profiling Source: https://www.graphql-java.com/documentation/profiler Enable profiling for a GraphQL execution by setting the profileExecution flag to true on the ExecutionInput. ```java import graphql.ExecutionInput; import graphql.GraphQL; // ... GraphQL graphql = GraphQL.newGraphQL(schema).build(); ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query("query Hello { world }") .profileExecution(true) // Enable profiling .build(); graphql.execute(executionInput); ``` -------------------------------- ### GraphQL Query with Variables and Literals Source: https://www.graphql-java.com/documentation/scalars This query demonstrates the usage of variables and AST literals, which trigger different methods in a custom scalar's Coercing implementation. ```graphql mutation Contact($mainContact: Email!) { makeContact(mainContactEmail: $mainContact, backupContactEmail: "backup@company.com") { id mainContactEmail } } ``` -------------------------------- ### GraphQL Directive Definitions and Usage Source: https://www.graphql-java.com/documentation/directives Defines several directives and demonstrates how they can be chained on a field. Directives are applied in the order they are encountered in the schema. ```graphql directive @uppercase on FIELD_DEFINITION directive @lowercase on FIELD_DEFINITION directive @mixedcase on FIELD_DEFINITION directive @reversed on FIELD_DEFINITION type Query { lowerCaseValue : String @uppercase upperCaseValue : String @lowercase mixedCaseValue : String @mixedcase # # directives are applied in order hence this will be lower, then upper, then mixed then reversed # allTogetherNow : String @lowercase @uppercase @mixedcase @reversed } ``` -------------------------------- ### Executing GraphQL Query with DataLoader Source: https://www.graphql-java.com/documentation/batching Constructs an `ExecutionInput` object, including the query and the `DataLoaderRegistry`, then executes the query using the `GraphQL` instance. The result contains the data fetched via batched operations. ```java ExecutionInput executionInput = newExecutionInput() .query(getQuery()) .dataLoaderRegistry(registry) .build(); ExecutionResult executionResult = graphQL.execute(executionInput); ``` -------------------------------- ### Directive with All Possible Locations Source: https://www.graphql-java.com/documentation/directives Illustrates a directive that can be applied to all eight possible locations within a GraphQL document, including queries, mutations, fields, and fragments. ```graphql type @foo on QUERY | MUTATION | SUBSCRIPTION | FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT | VARIABLE_DEFINITION query someQuery( $var: String @foo # Variable definition ) @foo # Query { field @foo ... on Query @foo { # Inline fragment field } ...someFragment @foo # Fragment spread } fragment someFragment @foo { # Fragment field } mutation someMutation @foo { # Mutation field } subscription someSubscription @foo { # Subscription field } ``` -------------------------------- ### Apply @auth Directive to Multiple Fields Source: https://www.graphql-java.com/documentation/directives Demonstrates applying the `@auth` directive to fields across different types to enforce role-based access control. ```graphql directive @auth(role : String!) on FIELD_DEFINITION type Employee id : ID name : String! startDate : String! salary : Float @auth(role : "manager") } type Department { id : ID name : String yearlyOperatingBudget : Float @auth(role : "manager") monthlyMarketingBudget : Float @auth(role : "manager") } ``` -------------------------------- ### Map Data to DTOs in Data Fetcher Source: https://www.graphql-java.com/documentation/data-mapping Implement a method to map data from multiple sources (ProductInfo, ProductCostInfo, ProductTaxInfo) into a list of ProductDTO objects. This creates a unified view for the GraphQL engine. ```java private List mapDataTogetherViaDTO(List productInfo, List productCostInfo, List productTaxInfo) { List unifiedView = new ArrayList<>(); for (int i = 0; i < productInfo.size(); i++) { ProductInfo info = productInfo.get(i); ProductCostInfo cost = productCostInfo.get(i); ProductTaxInfo tax = productTaxInfo.get(i); ProductDTO productDTO = new ProductDTO( info.getId(), info.getName(), info.getDescription(), cost.getCost(), tax.getTax() ); unifiedView.add(productDTO); } return unifiedView; } ``` -------------------------------- ### Add graphql-java Development Build with Gradle Source: https://www.graphql-java.com/documentation/getting-started Use the latest development build of graphql-java in your Gradle project by specifying the version placeholder. Ensure mavenCentral() is configured. ```gradle repositories { mavenCentral() } dependencies { implementation 'com.graphql-java:graphql-java:INSERT_LATEST_VERSION_HERE' } ``` ```gradle repositories { mavenCentral() } dependencies { implementation("com.graphql-java:graphql-java:INSERT_LATEST_VERSION_HERE") } ``` -------------------------------- ### Implementing a Mutation Data Fetcher Source: https://www.graphql-java.com/documentation/execution This data fetcher executes the mutation logic, handling input arguments as maps and converting them to Java objects before interacting with the data store. ```java private DataFetcher mutationDataFetcher() { return new DataFetcher() { @Override public Review get(DataFetchingEnvironment environment) { // // The graphql specification dictates that input object arguments MUST // be maps. You can convert them to POJOs inside the data fetcher if that // suits your code better // // See http://facebook.github.io/graphql/October2016/#sec-Input-Objects // Map episodeInputMap = environment.getArgument("episode"); Map reviewInputMap = environment.getArgument("review"); // // in this case we have type safe Java objects to call our backing code with // EpisodeInput episodeInput = EpisodeInput.fromMap(episodeInputMap); ReviewInput reviewInput = ReviewInput.fromMap(reviewInputMap); // make a call to your store to mutate your database Review updatedReview = reviewStore().update(episodeInput, reviewInput); // this returns a new view of the data return updatedReview; } }; } ``` -------------------------------- ### Declare and Use Custom Directive Source: https://www.graphql-java.com/documentation/directives Declare a custom directive like `@auth` with its arguments and specify its location (e.g., FIELD_DEFINITION). Then, apply the directive to a field definition. ```graphql # This is a directive declaration directive @auth(role : String!) on FIELD_DEFINITION type Employee id : ID # and this is a usage of that declared directive salary : Float @auth(role : "manager") } ``` -------------------------------- ### Define GraphQL Schema using SDL Source: https://www.graphql-java.com/documentation/schema Use Schema Definition Language (SDL) for a declarative way to define your GraphQL schema. This is the recommended approach when unsure. ```graphql type Foo { bar: String } ``` -------------------------------- ### Monitor Incoming Traffic with InputInterceptor Source: https://www.graphql-java.com/documentation/upgrade-notes Use LegacyCoercingInputInterceptor to monitor incoming requests and detect legacy values. A callback can be invoked for actions like emitting metrics. ```java InputInterceptor legacyInputInterceptor = LegacyCoercingInputInterceptor.observesValues((inputValue, graphQLInputType) -> { emitAMetric(inputValue, graphQLInputType); }); ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query("query { exampleField }") .graphQLContext(Map.of(InputInterceptor.class, legacyInputInterceptor)) .build(); ``` -------------------------------- ### Configure MaxQueryDepthInstrumentation Source: https://www.graphql-java.com/documentation/instrumentation Instantiate and apply MaxQueryDepthInstrumentation when building your GraphQL instance to set a maximum allowed query depth. ```java GraphQL.newGraphQL(schema) .instrumentation(new MaxQueryDepthInstrumentation(4)) .build(); ``` -------------------------------- ### DataLoaderDispatcherInstrumentation with Options Source: https://www.graphql-java.com/documentation/batching Configures `DataLoaderDispatcherInstrumentation` with options to include statistics for batching efficiency. This instrumentation dispatches all data loaders as GraphQL query levels are executed. ```java // // this instrumentation implementation will dispatch all the data loaders // as each level of the graphql query is executed and hence make batched objects // available to the query and the associated DataFetchers // // In this case we use options to make it keep statistics on the batching efficiency // DataLoaderDispatcherInstrumentationOptions options = DataLoaderDispatcherInstrumentationOptions .newOptions().includeStatistics(true); DataLoaderDispatcherInstrumentation dispatcherInstrumentation = new DataLoaderDispatcherInstrumentation(options); ``` -------------------------------- ### Add graphql-java Dependency with Gradle Source: https://www.graphql-java.com/documentation/getting-started Include the graphql-java library in your Gradle project by adding the specified dependency to your build file. Ensure mavenCentral() is configured in your repositories. ```gradle repositories { mavenCentral() } dependencies { implementation 'com.graphql-java:graphql-java:25.0' } ``` ```gradle repositories { mavenCentral() } dependencies { implementation("com.graphql-java:graphql-java:25.0") } ``` -------------------------------- ### Runtime JVM Representation of Complex List Input Source: https://www.graphql-java.com/documentation/data-mapping Illustrates the runtime JVM representation for the complex 'Person' input type and the 'contacts' query. It shows nested `java.util.List` and `java.util.Map` structures. ```java List.of( Map.of("name", "Brad", "age", 42, "friends", List.of( Map.of("name", "Bill", "age", 17, "friends", List.of() ) ) ), Map.of("name", "Andreas", "age", 34, "friends", List.of( Map.of("name", "Ted", "age", 15, "friends", List.of() ) ) ) ); ```