@@ -344,6 +344,105 @@ Example: [GraphQL Test](src/test/groovy/graphql/GraphQLTest.groovy)
344344More complex examples: [StarWars query tests](src/ test/ groovy/ graphql/ StarWarsQueryTest . groovy)
345345
346346
347+ #### Causing mutation during execution
348+
349+ A good starting point to learn more about mutating data in graphql is [http: // graphql.org/learn/queries/#mutations](http://graphql.org/learn/queries/#mutations)
350+
351+ In essence you need to define a `GraphQLObjectType ` that takes arguments as input. Those arguments are what you can use to mutate your data store
352+ via the data fetcher invoked.
353+
354+ The mutation is invoked via a query like :
355+
356+ ```graphql
357+ mutation CreateReviewForEpisode($ep: Episode ! , $review: ReviewInput ! ) {
358+ createReview(episode: $ep, review: $review) {
359+ stars
360+ commentary
361+ }
362+ }
363+ ```
364+
365+ You need to send in arguments during that mutation operation, in this case for the variables for `$ep` and `$review`
366+
367+ You would create types like this to handle this mutation :
368+
369+ ```java
370+ GraphQLInputObjectType episodeType = GraphQLInputObjectType . newInputObject()
371+ .name(" Episode" )
372+ .field(newInputObjectField()
373+ .name(" episodeNumber" )
374+ .type(Scalars . GraphQLInt ))
375+ .build();
376+
377+ GraphQLInputObjectType reviewInputType = GraphQLInputObjectType . newInputObject()
378+ .name(" ReviewInput" )
379+ .field(newInputObjectField()
380+ .name(" stars" )
381+ .type(Scalars . GraphQLString )
382+ .name(" commentary" )
383+ .type(Scalars . GraphQLString ))
384+ .build();
385+
386+ GraphQLObjectType reviewType = newObject()
387+ .name(" Review" )
388+ .field(newFieldDefinition()
389+ .name(" stars" )
390+ .type(GraphQLString ))
391+ .field(newFieldDefinition()
392+ .name(" commentary" )
393+ .type(GraphQLString ))
394+ .build();
395+
396+ GraphQLObjectType createReviewForEpisodeMutation = newObject()
397+ .name(" CreateReviewForEpisodeMutation" )
398+ .field(newFieldDefinition()
399+ .name(" createReview" )
400+ .type(reviewType)
401+ .argument(newArgument()
402+ .name(" episode" )
403+ .type(episodeType)
404+ )
405+ .argument(newArgument()
406+ .name(" review" )
407+ .type(reviewInputType)
408+ )
409+ .dataFetcher(mutationDataFetcher())
410+ )
411+ .build();
412+
413+ GraphQLSchema schema = GraphQLSchema . newSchema()
414+ .query(queryType)
415+ .mutation(createReviewForEpisodeMutation)
416+ .build();
417+
418+ ```
419+
420+ Notice that the input arguments are of type `GraphQLInputObjectType `. This is important. Input arguments can ONLY be of that type
421+ and you cannot use output types such as `GraphQLObjectType `. Scalars types are consider both input and output types.
422+
423+ The data fetcher here is responsible for executing the mutation and returning some sensible output values.
424+
425+ ```java
426+ private DataFetcher mutationDataFetcher() {
427+ return new DataFetcher () {
428+ @Override
429+ public Review get (DataFetchingEnvironment environment ) {
430+ Episode episode = environment. getArgument(" episode" );
431+ ReviewInput review = environment. getArgument(" review" );
432+
433+ // make a call to your store to mutate your database
434+ Review updatedReview = reviewStore(). update(episode, review);
435+
436+ // this returns a new view of the data
437+ return updatedReview;
438+ }
439+ };
440+ }
441+ ```
442+
443+ Notice how it calls a data store to mutate the backing database and then returns a `Review ` object that can be used as the output values
444+ to the caller.
445+
347446#### Execution strategies
348447
349448All fields in a SelectionSet are executed serially per default .
@@ -420,6 +519,117 @@ public Object executeOperation(@RequestBody Map body) {
420519}
421520```
422521
522+ ### Schema IDL support
523+
524+ This library allows for "schema driven" development of graphql applications.
525+
526+ It allows you to compile a set of schema files into a executable `GraphqlSchema`.
527+
528+
529+ So given a graphql schema input file like :
530+
531+ ```graphql
532+
533+ schema {
534+ query: QueryType
535+ }
536+
537+ type QueryType {
538+ hero(episode: Episode): Character
539+ human(id : String) : Human
540+ droid(id: ID!): Droid
541+ }
542+
543+
544+ enum Episode {
545+ NEWHOPE
546+ EMPIRE
547+ JEDI
548+ }
549+
550+ interface Character {
551+ id: ID!
552+ name: String!
553+ friends: [Character]
554+ appearsIn: [Episode]!
555+ }
556+
557+ type Human implements Character {
558+ id: ID!
559+ name: String!
560+ friends: [Character]
561+ appearsIn: [Episode]!
562+ homePlanet: String
563+ }
564+
565+ type Droid implements Character {
566+ id: ID!
567+ name: String!
568+ friends: [Character]
569+ appearsIn: [Episode]!
570+ primaryFunction: String
571+ }
572+
573+
574+ ```
575+
576+ You could compile and generate an executable schema via
577+
578+ ```java
579+ SchemaCompiler schemaCompiler = new SchemaCompiler();
580+ SchemaGenerator schemaGenerator = new SchemaGenerator();
581+
582+ File schemaFile = loadSchema("starWarsSchema.graphqls");
583+
584+ TypeDefinitionRegistry typeRegistry = schemaCompiler.compile(schemaFile);
585+ RuntimeWiring wiring = buildRuntimeWiring();
586+ GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring);
587+
588+ ```
589+
590+ The static schema definition file has the field and type definitions but you need a runtime wiring to make
591+ it a truly executable schema.
592+
593+ The runtime wiring contains `DataFetchers`, `TypeResolvers` and custom `Scalars` that are needed to make a fully
594+ executable schema.
595+
596+ You wire this together using this builder pattern
597+
598+ ```java
599+
600+ RuntimeWiring buildRuntimeWiring() {
601+ return RuntimeWiring.newRuntimeWiring()
602+ .scalar(CustomScalar)
603+ // this uses builder function lambda syntax
604+ .type(typeWiring -> typeWiring.typeName("QueryType")
605+ .dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo()))
606+ .dataFetcher("human", StarWarsData.getHumanDataFetcher())
607+ .dataFetcher("droid", StarWarsData.getDroidDataFetcher())
608+ )
609+ .type(typeWiring -> typeWiring.typeName("Human")
610+ .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())
611+ )
612+ // you can use builder syntax if you don' t like the lambda syntax
613+ .type(typeWiring - > typeWiring. typeName(" Droid" )
614+ .dataFetcher(" friends" , StarWarsData . getFriendsDataFetcher())
615+ )
616+ // or full builder syntax if that takes your fancy
617+ .type(
618+ newTypeWiring(" Character" )
619+ .typeResolver(StarWarsData . getCharacterTypeResolver())
620+ .build()
621+ )
622+ .build();
623+ }
624+
625+
626+ ```
627+
628+ NOTE : IDL is not currently part of the [formal graphql spec](https: // facebook.github.io/graphql/#sec-Appendix-Grammar-Summary.Query-Document).
629+ The implementation in this library is based off the [reference implementation](https: // github.com/graphql/graphql-js). However plenty of
630+ code out there is based on this IDL syntax and hence you can be fairly confident that you are building on solid technology ground.
631+
632+
423633#### Contributions
424634
425635Every contribution to make this project better is welcome: Thank you!
0 commit comments