diff --git a/src/main/java/graphql/Assert.java b/src/main/java/graphql/Assert.java index 5bb3bfbe37..259b22cc5d 100644 --- a/src/main/java/graphql/Assert.java +++ b/src/main/java/graphql/Assert.java @@ -14,11 +14,24 @@ public static T assertNeverCalled() { throw new AssertException("Should never been called"); } + public static T assertShouldNeverHappen(String errorMessage) { + throw new AssertException("Internal error: should never happen: " + errorMessage); + } + + public static T assertShouldNeverHappen() { + throw new AssertException("Internal error: should never happen"); + } + public static Collection assertNotEmpty(Collection c, String errorMessage) { if (c == null || c.isEmpty()) throw new AssertException(errorMessage); return c; } + public static void assertTrue(boolean condition, String errorMessage) { + if (condition) return; + throw new AssertException(errorMessage); + } + private static final String invalidNameErrorMessage = "Name must be non-null, non-empty and match [_A-Za-z][_0-9A-Za-z]*"; /** diff --git a/src/main/java/graphql/introspection/IntrospectionResultToSchema.java b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java new file mode 100644 index 0000000000..06c74bbba2 --- /dev/null +++ b/src/main/java/graphql/introspection/IntrospectionResultToSchema.java @@ -0,0 +1,232 @@ +package graphql.introspection; + +import graphql.PublicApi; +import graphql.language.Comment; +import graphql.language.Document; +import graphql.language.EnumTypeDefinition; +import graphql.language.EnumValueDefinition; +import graphql.language.FieldDefinition; +import graphql.language.InputObjectTypeDefinition; +import graphql.language.InputValueDefinition; +import graphql.language.InterfaceTypeDefinition; +import graphql.language.ListType; +import graphql.language.NonNullType; +import graphql.language.ObjectTypeDefinition; +import graphql.language.OperationTypeDefinition; +import graphql.language.SchemaDefinition; +import graphql.language.SourceLocation; +import graphql.language.StringValue; +import graphql.language.Type; +import graphql.language.TypeDefinition; +import graphql.language.TypeName; +import graphql.language.UnionTypeDefinition; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static graphql.Assert.assertNotNull; +import static graphql.Assert.assertShouldNeverHappen; +import static graphql.Assert.assertTrue; + +@PublicApi +public class IntrospectionResultToSchema { + + + @SuppressWarnings("unchecked") + public Document createSchemaDefinition(Map introspectionResult) { + assertTrue(introspectionResult.get("__schema") != null, "__schema expected"); + Map schema = (Map) introspectionResult.get("__schema"); + + SchemaDefinition schemaDefinition = new SchemaDefinition(); + + Map queryType = (Map) schema.get("queryType"); + assertNotNull(queryType, "queryType expected"); + TypeName query = new TypeName((String) queryType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("query", query)); + + Map mutationType = (Map) schema.get("mutationType"); + if (mutationType != null) { + TypeName mutation = new TypeName((String) mutationType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("mutation", mutation)); + } + + Map subscriptionType = (Map) schema.get("subscriptionType"); + if (subscriptionType != null) { + TypeName subscription = new TypeName((String) subscriptionType.get("name")); + schemaDefinition.getOperationTypeDefinitions().add(new OperationTypeDefinition("subscription", subscription)); + } + + Document document = new Document(); + document.getDefinitions().add(schemaDefinition); + + List> types = (List>) schema.get("types"); + for (Map type : types) { + TypeDefinition typeDefinition = createTypeDefinition(type); + if (typeDefinition == null) continue; + document.getDefinitions().add(typeDefinition); + } + + return document; + } + + private TypeDefinition createTypeDefinition(Map type) { + String kind = (String) type.get("kind"); + String name = (String) type.get("name"); + if (name.startsWith("__")) return null; + switch (kind) { + case "INTERFACE": + return createInterface(type); + case "OBJECT": + return createObject(type); + case "UNION": + return createUnion(type); + case "ENUM": + return createEnum(type); + case "INPUT_OBJECT": + return createInputObject(type); + case "SCALAR": + // todo don't ignore all scalars + return null; + default: + return assertShouldNeverHappen("unexpected kind " + kind); + } + } + + + @SuppressWarnings("unchecked") + UnionTypeDefinition createUnion(Map input) { + assertTrue(input.get("kind").equals("UNION"), "wrong input"); + + UnionTypeDefinition unionTypeDefinition = new UnionTypeDefinition((String) input.get("name")); + unionTypeDefinition.setComments(toComment((String) input.get("description"))); + + List> possibleTypes = (List>) input.get("possibleTypes"); + + for (Map possibleType : possibleTypes) { + TypeName typeName = new TypeName((String) possibleType.get("name")); + unionTypeDefinition.getMemberTypes().add(typeName); + } + + return unionTypeDefinition; + } + + @SuppressWarnings("unchecked") + EnumTypeDefinition createEnum(Map input) { + assertTrue(input.get("kind").equals("ENUM"), "wrong input"); + + EnumTypeDefinition enumTypeDefinition = new EnumTypeDefinition((String) input.get("name")); + enumTypeDefinition.setComments(toComment((String) input.get("description"))); + + List> enumValues = (List>) input.get("enumValues"); + + for (Map enumValue : enumValues) { + + EnumValueDefinition enumValueDefinition = new EnumValueDefinition((String) enumValue.get("name")); + enumValueDefinition.setComments(toComment((String) enumValue.get("description"))); + enumTypeDefinition.getEnumValueDefinitions().add(enumValueDefinition); + } + + return enumTypeDefinition; + } + + @SuppressWarnings("unchecked") + InterfaceTypeDefinition createInterface(Map input) { + assertTrue(input.get("kind").equals("INTERFACE"), "wrong input"); + + InterfaceTypeDefinition interfaceTypeDefinition = new InterfaceTypeDefinition((String) input.get("name")); + interfaceTypeDefinition.setComments(toComment((String) input.get("description"))); + List> fields = (List>) input.get("fields"); + interfaceTypeDefinition.getFieldDefinitions().addAll(createFields(fields)); + + return interfaceTypeDefinition; + + } + + @SuppressWarnings("unchecked") + InputObjectTypeDefinition createInputObject(Map input) { + assertTrue(input.get("kind").equals("INPUT_OBJECT"), "wrong input"); + + InputObjectTypeDefinition inputObjectTypeDefinition = new InputObjectTypeDefinition((String) input.get("name")); + inputObjectTypeDefinition.setComments(toComment((String) input.get("description"))); + List> fields = (List>) input.get("inputFields"); + List inputValueDefinitions = createInputValueDefinitions(fields); + inputObjectTypeDefinition.getInputValueDefinitions().addAll(inputValueDefinitions); + + return inputObjectTypeDefinition; + } + + @SuppressWarnings("unchecked") + ObjectTypeDefinition createObject(Map input) { + assertTrue(input.get("kind").equals("OBJECT"), "wrong input"); + + ObjectTypeDefinition objectTypeDefinition = new ObjectTypeDefinition((String) input.get("name")); + objectTypeDefinition.setComments(toComment((String) input.get("description"))); + List> fields = (List>) input.get("fields"); + + objectTypeDefinition.getFieldDefinitions().addAll(createFields(fields)); + + return objectTypeDefinition; + } + + private List createFields(List> fields) { + List result = new ArrayList<>(); + for (Map field : fields) { + FieldDefinition fieldDefinition = new FieldDefinition((String) field.get("name")); + fieldDefinition.setComments(toComment((String) field.get("description"))); + fieldDefinition.setType(createTypeIndirection((Map) field.get("type"))); + + List> args = (List>) field.get("args"); + List inputValueDefinitions = createInputValueDefinitions(args); + fieldDefinition.getInputValueDefinitions().addAll(inputValueDefinitions); + result.add(fieldDefinition); + } + return result; + } + + @SuppressWarnings("unchecked") + private List createInputValueDefinitions(List> args) { + List result = new ArrayList<>(); + for (Map arg : args) { + Type argType = createTypeIndirection((Map) arg.get("type")); + InputValueDefinition inputValueDefinition = new InputValueDefinition((String) arg.get("name"), argType); + inputValueDefinition.setComments(toComment((String) arg.get("description"))); + + if (arg.get("defaultValue") != null) { + StringValue defaultValue = new StringValue((String) arg.get("defaultValue")); + inputValueDefinition.setDefaultValue(defaultValue); + } + result.add(inputValueDefinition); + } + return result; + } + + @SuppressWarnings("unchecked") + private Type createTypeIndirection(Map type) { + String kind = (String) type.get("kind"); + switch (kind) { + case "INTERFACE": + case "OBJECT": + case "UNION": + case "ENUM": + case "INPUT_OBJECT": + case "SCALAR": + return new TypeName((String) type.get("name")); + case "NON_NULL": + return new NonNullType(createTypeIndirection((Map) type.get("ofType"))); + case "LIST": + return new ListType(createTypeIndirection((Map) type.get("ofType"))); + default: + return assertShouldNeverHappen("Unknown kind " + kind); + } + } + + private List toComment(String description) { + if (description == null) return Collections.emptyList(); + Comment comment = new Comment(description, new SourceLocation(1, 1)); + return Arrays.asList(comment); + } + +} diff --git a/src/main/java/graphql/language/AstPrinter.java b/src/main/java/graphql/language/AstPrinter.java index c32883f97a..e596d07bf1 100644 --- a/src/main/java/graphql/language/AstPrinter.java +++ b/src/main/java/graphql/language/AstPrinter.java @@ -89,12 +89,16 @@ private static NodePrinter directiveLocation() { } private static NodePrinter enumTypeDefinition() { - return (out, node) -> out.printf("%s", spaced( - "enum", - node.getName(), - directives(node.getDirectives()), - block(node.getEnumValueDefinitions()) - )); + return (out, node) -> { + out.printf("%s", comments(node)); + out.printf("%s", + spaced( + "enum", + node.getName(), + directives(node.getDirectives()), + block(node.getEnumValueDefinitions()) + )); + }; } private static NodePrinter enumValue() { @@ -102,7 +106,10 @@ private static NodePrinter enumValue() { } private static NodePrinter enumValueDefinition() { - return (out, node) -> out.printf("%s", node.getName()); + return (out, node) -> { + out.printf("%s", comments(node)); + out.printf("%s", node.getName()); + }; } private static NodePrinter field() { @@ -124,16 +131,30 @@ private static NodePrinter field() { private static NodePrinter fieldDefinition() { return (out, node) -> { - String args = join(node.getInputValueDefinitions(), ", "); out.printf("%s", comments(node)); - out.printf("%s", node.getName() + - wrap("(", args, ")") + - ": " + type(node.getType()) + - directives(node.getDirectives()) - ); + String args; + if (hasComments(node.getInputValueDefinitions())) { + args = join(node.getInputValueDefinitions(), "\n"); + out.printf("%s", node.getName() + + wrap("(\n", args, "\n)") + + ": " + type(node.getType()) + + directives(node.getDirectives()) + ); + } else { + args = join(node.getInputValueDefinitions(), ", "); + out.printf("%s", node.getName() + + wrap("(", args, ")") + + ": " + type(node.getType()) + + directives(node.getDirectives()) + ); + } }; } + private static boolean hasComments(List nodes) { + return nodes.stream().filter(it -> it.getComments().size() > 0).count() > 0; + } + private static NodePrinter fragmentDefinition() { return (out, node) -> { String name = node.getName(); @@ -461,7 +482,6 @@ static String wrap(String start, Node maybeNode, String end) { * This will pretty print the AST node in graphql language format * * @param node the AST node to print - * * @return the printed node in graphql language format */ public static String printAst(Node node) { diff --git a/src/main/java/graphql/language/InputValueDefinition.java b/src/main/java/graphql/language/InputValueDefinition.java index 51904d09fc..6bb69cea8e 100644 --- a/src/main/java/graphql/language/InputValueDefinition.java +++ b/src/main/java/graphql/language/InputValueDefinition.java @@ -39,7 +39,7 @@ public Value getDefaultValue() { return defaultValue; } - public void setValue(Value defaultValue) { + public void setDefaultValue(Value defaultValue) { this.defaultValue = defaultValue; } diff --git a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java index a9a2c26b90..98f5277938 100644 --- a/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java +++ b/src/main/java/graphql/parser/GraphqlAntlrToLanguage.java @@ -537,7 +537,7 @@ public Void visitInputValueDefinition(GraphqlParser.InputValueDefinitionContext InputValueDefinition def = new InputValueDefinition(ctx.name().getText()); newNode(def, ctx); if (ctx.defaultValue() != null) { - def.setValue(getValue(ctx.defaultValue().value())); + def.setDefaultValue(getValue(ctx.defaultValue().value())); } for (ContextEntry contextEntry : contextStack) { if (contextEntry.contextProperty == ContextProperty.FieldDefinition) { diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy new file mode 100644 index 0000000000..c8002d93c2 --- /dev/null +++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy @@ -0,0 +1,531 @@ +package graphql.introspection + +import graphql.language.AstPrinter +import graphql.language.Document +import graphql.language.EnumTypeDefinition +import graphql.language.InputObjectTypeDefinition +import graphql.language.InterfaceTypeDefinition +import graphql.language.ObjectTypeDefinition +import graphql.language.UnionTypeDefinition +import groovy.json.JsonSlurper +import spock.lang.Specification + +class IntrospectionResultToSchemaTest extends Specification { + + def introspectionResultToSchema = new IntrospectionResultToSchema() + + def "create object"() { + def input = """ { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "hero", + "description": null, + "args": [ + { + "name": "episode", + "description": "comment about episode", + "type": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "foo", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": "bar" + } + ], + "type": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + ObjectTypeDefinition objectTypeDefinition = introspectionResultToSchema.createObject(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(objectTypeDefinition) + + then: + result == """type QueryType { + hero( + #comment about episode + episode: Episode + foo: String = \"bar\" + ): Character +}""" + + } + + def "create interface"() { + def input = """ { + "kind": "INTERFACE", + "name": "Character", + "description": "A character in the Star Wars Trilogy", + "fields": [ + { + "name": "id", + "description": "The id of the character.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the character.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the character, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + } + ] + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + InterfaceTypeDefinition interfaceTypeDefinition = introspectionResultToSchema.createInterface(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(interfaceTypeDefinition) + + then: + result == """#A character in the Star Wars Trilogy +interface Character { + #The id of the character. + id: String! + #The name of the character. + name: String + #The friends of the character, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] +}""" + + } + + def "create enum"() { + def input = """ { + "kind": "ENUM", + "name": "Episode", + "description": "One of the films in the Star Wars Trilogy", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "NEWHOPE", + "description": "Released in 1977.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "EMPIRE", + "description": "Released in 1980.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "JEDI", + "description": "Released in 1983.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + EnumTypeDefinition interfaceTypeDefinition = introspectionResultToSchema.createEnum(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(interfaceTypeDefinition) + + then: + result == """#One of the films in the Star Wars Trilogy +enum Episode { + #Released in 1977. + NEWHOPE + #Released in 1980. + EMPIRE + #Released in 1983. + JEDI +}""" + + } + + def "create union"() { + def input = """ { + "kind": "UNION", + "name": "Everything", + "description": "all the stuff", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + ] + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + UnionTypeDefinition unionTypeDefinition = introspectionResultToSchema.createUnion(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(unionTypeDefinition) + + then: + result == """#all the stuff +union Everything = Character | Episode""" + + } + + def "create input object"() { + def input = """ { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "description": "input for characters", + "fields": null, + "inputFields": [ + { + "name": "firstName", + "description": "first name", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "lastName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "family", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + } + """ + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + InputObjectTypeDefinition inputObjectTypeDefinition = introspectionResultToSchema.createInputObject(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(inputObjectTypeDefinition) + + then: + result == """#input for characters +CharacterInput { + #first name + firstName: String + lastName: String + family: Boolean +}""" + } + + + def "create schema"() { + def input = """{ + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": {"name":"MutationType"}, + "subscriptionType": {"name":"SubscriptionType"}, + "types": [ + ] + }""" + def slurper = new JsonSlurper() + def parsed = slurper.parseText(input) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType + mutation: MutationType + subscription: SubscriptionType +} +""" + + } + + def "test starwars introspection result"() { + given: + String starwars = this.getClass().getResource('/starwars-introspection.json').text + def slurper = new JsonSlurper() + def parsed = slurper.parseText(starwars) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType +} + +type QueryType { + hero( + #If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode. + episode: Episode + ): Character + human( + #id of the human + id: String! + ): Human + droid( + #id of the droid + id: String! + ): Droid +} + +#A character in the Star Wars Trilogy +interface Character { + #The id of the character. + id: String! + #The name of the character. + name: String + #The friends of the character, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] +} + +#One of the films in the Star Wars Trilogy +enum Episode { + #Released in 1977. + NEWHOPE + #Released in 1980. + EMPIRE + #Released in 1983. + JEDI +} + +#A humanoid creature in the Star Wars universe. +type Human { + #The id of the human. + id: String! + #The name of the human. + name: String + #The friends of the human, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] + #The home planet of the human, or null if unknown. + homePlanet: String +} + +#A mechanical creature in the Star Wars universe. +type Droid { + #The id of the droid. + id: String! + #The name of the droid. + name: String + #The friends of the droid, or an empty list if they have none. + friends: [Character] + #Which movies they appear in. + appearsIn: [Episode] + #The primary function of the droid. + primaryFunction: String +} +""" + } + + def "test simpsons introspection result"() { + given: + String simpsons = this.getClass().getResource('/simpsons-introspection.json').text + def slurper = new JsonSlurper() + def parsed = slurper.parseText(simpsons) + + when: + Document document = introspectionResultToSchema.createSchemaDefinition(parsed) + AstPrinter astPrinter = new AstPrinter() + def result = astPrinter.printAst(document) + + then: + result == """schema { + query: QueryType + mutation: MutationType +} + +type QueryType { + character(firstName: String): Character + characters: [Character] + episodes: [Episode] + search(searchFor: String): [Everything] +} + +type Character { + id: ID! + firstName: String + lastName: String + family: Boolean + episodes: [Episode] +} + +type Episode { + id: ID! + name: String + season: Season + number: Int + numberOverall: Int + characters: [Character] +} + +# Simpson seasons +enum Season { + # the beginning + Season1 + Season2 + Season3 + Season4 + # Another one + Season5 + Season6 + Season7 + Season8 + # Not really the last one :-) + Season9 +} + +union Everything = Character | Episode + +type MutationType { + addCharacter(character: CharacterInput): MutationResult +} + +type MutationResult { + success: Boolean +} + +CharacterInput { + firstName: String + lastName: String + family: Boolean +} +""" + } +} + diff --git a/src/test/groovy/graphql/parser/IDLParserTest.groovy b/src/test/groovy/graphql/parser/IDLParserTest.groovy index fa91517ff5..a619fb9c7b 100644 --- a/src/test/groovy/graphql/parser/IDLParserTest.groovy +++ b/src/test/groovy/graphql/parser/IDLParserTest.groovy @@ -372,7 +372,7 @@ directive @DirectiveName(arg1:String arg2:Int=23) on FIELD | QUERY List commentContent(List comments) { - comments.stream().map {c -> c.content}.collect(Collectors.toList()) + comments.stream().map { c -> c.content }.collect(Collectors.toList()) } def "comment support on definitions"() { @@ -447,7 +447,6 @@ input Gun { commentContent(schemaDef.comments) == ["schema comment 1", " schema comment 2 with leading spaces"] commentContent(schemaDef.operationTypeDefinitions[0].comments) == [" schema operation comment query"] commentContent(schemaDef.operationTypeDefinitions[1].comments) == [" schema operation comment mutation"] - ObjectTypeDefinition typeDef = document.definitions[1] as ObjectTypeDefinition commentContent(typeDef.comments) == [" type query comment 1", " type query comment 2"] commentContent(typeDef.fieldDefinitions[0].comments) == [" query field 'hero' comment"] @@ -473,4 +472,26 @@ input Gun { } + def "comments on field arguments"() { + def input = """ + type QueryType { + hero( + #comment about episode + episode: Episode + # second + foo: String = \"bar\" + ): Character + } +""" + when: + def document = new Parser().parseDocument(input) + + then: + ObjectTypeDefinition typeDef = document.definitions[0] as ObjectTypeDefinition + def inputValueDefinitions = typeDef.fieldDefinitions[0].inputValueDefinitions + commentContent(inputValueDefinitions[0].comments) == ["comment about episode"] + commentContent(inputValueDefinitions[1].comments) == [" second"] + } + } + diff --git a/src/test/resources/simpsons-introspection.json b/src/test/resources/simpsons-introspection.json new file mode 100644 index 0000000000..447a6c8641 --- /dev/null +++ b/src/test/resources/simpsons-introspection.json @@ -0,0 +1,1298 @@ +{ + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": { + "name": "MutationType" + }, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "character", + "description": null, + "args": [ + { + "name": "firstName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "search", + "description": null, + "args": [ + { + "name": "searchFor", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "UNION", + "name": "Everything", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Character", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "firstName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "lastName", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "family", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "episodes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "ID", + "description": "Built-in ID", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "String", + "description": "Built-in String", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "Built-in Boolean", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "description": null, + "fields": [ + { + "name": "id", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "season", + "description": null, + "args": [], + "type": { + "kind": "ENUM", + "name": "Season", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "number", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "numberOverall", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "characters", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "Season", + "description": " Simpson seasons", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "Season1", + "description": " the beginning", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season2", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season3", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season4", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season5", + "description": " Another one", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season6", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season7", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season8", + "description": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "Season9", + "description": " Not really the last one :-)", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Int", + "description": "Built-in Int", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "UNION", + "name": "Everything", + "description": null, + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Character", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Episode", + "ofType": null + } + ] + }, + { + "kind": "OBJECT", + "name": "MutationType", + "description": null, + "fields": [ + { + "name": "addCharacter", + "description": null, + "args": [ + { + "name": "character", + "description": null, + "type": { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MutationResult", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "MutationResult", + "description": null, + "fields": [ + { + "name": "success", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "CharacterInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "firstName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "lastName", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "family", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "'A list of all directives supported by this server.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "'If this server support subscription, the type that subscription operations will be rooted at.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": null, + "fields": [ + { + "name": "kind", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given __Type is", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "An enum describing valid locations where a directive can be placed", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Indicates the directive is valid on queries.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Indicates the directive is valid on mutations.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Indicates the directive is valid on fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Indicates the directive is valid on fragment definitions.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Indicates the directive is valid on fragment spreads.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Indicates the directive is valid on inline fragments.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/starwars-introspection.json b/src/test/resources/starwars-introspection.json new file mode 100644 index 0000000000..1a98643aa9 --- /dev/null +++ b/src/test/resources/starwars-introspection.json @@ -0,0 +1,1257 @@ +{ + "__schema": { + "queryType": { + "name": "QueryType" + }, + "mutationType": null, + "subscriptionType": null, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "description": null, + "fields": [ + { + "name": "hero", + "description": null, + "args": [ + { + "name": "episode", + "description": "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.", + "type": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "human", + "description": null, + "args": [ + { + "name": "id", + "description": "id of the human", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "droid", + "description": null, + "args": [ + { + "name": "id", + "description": "id of the droid", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INTERFACE", + "name": "Character", + "description": "A character in the Star Wars Trilogy", + "fields": [ + { + "name": "id", + "description": "The id of the character.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the character.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the character, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": [ + { + "kind": "OBJECT", + "name": "Human", + "ofType": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "ofType": null + } + ] + }, + { + "kind": "SCALAR", + "name": "String", + "description": "Built-in String", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "Episode", + "description": "One of the films in the Star Wars Trilogy", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "NEWHOPE", + "description": "Released in 1977.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "EMPIRE", + "description": "Released in 1980.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "JEDI", + "description": "Released in 1983.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Human", + "description": "A humanoid creature in the Star Wars universe.", + "fields": [ + { + "name": "id", + "description": "The id of the human.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the human.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the human, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "homePlanet", + "description": "The home planet of the human, or null if unknown.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "Droid", + "description": "A mechanical creature in the Star Wars universe.", + "fields": [ + { + "name": "id", + "description": "The id of the droid.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the droid.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "friends", + "description": "The friends of the droid, or an empty list if they have none.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "appearsIn", + "description": "Which movies they appear in.", + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "Episode", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "primaryFunction", + "description": "The primary function of the droid.", + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Character", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Schema", + "description": "A GraphQL Introspection defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, the entry points for query, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that mutation operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "directives", + "description": "'A list of all directives supported by this server.", + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Directive" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionType", + "description": "'If this server support subscription, the type that subscription operations will be rooted at.", + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Type", + "description": null, + "fields": [ + { + "name": "kind", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "fields", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "interfaces", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "possibleTypes", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "enumValues", + "description": null, + "args": [ + { + "name": "includeDeprecated", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false" + } + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "inputFields", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ofType", + "description": null, + "args": [ + ], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "description": "An enum describing what kind of type a given __Type is", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "SCALAR", + "description": "Indicates this type is a scalar.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "OBJECT", + "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INTERFACE", + "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "UNION", + "description": "Indicates this type is a union. `possibleTypes` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "ENUM", + "description": "Indicates this type is an enum. `enumValues` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INPUT_OBJECT", + "description": "Indicates this type is an input object. `inputFields` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "LIST", + "description": "Indicates this type is a list. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "NON_NULL", + "description": "Indicates this type is a non-null. `ofType` is a valid field.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Field", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "defaultValue", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "Built-in Boolean", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "isDeprecated", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "deprecationReason", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "__Directive", + "description": null, + "fields": [ + { + "name": "name", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "description", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "locations", + "description": null, + "args": [ + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": null + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "args", + "description": null, + "args": [ + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue" + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "onOperation", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onFragment", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + }, + { + "name": "onField", + "description": null, + "args": [ + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": true, + "deprecationReason": "Use `locations`." + } + ], + "inputFields": null, + "interfaces": [ + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "description": "An enum describing valid locations where a directive can be placed", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "QUERY", + "description": "Indicates the directive is valid on queries.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "MUTATION", + "description": "Indicates the directive is valid on mutations.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FIELD", + "description": "Indicates the directive is valid on fields.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_DEFINITION", + "description": "Indicates the directive is valid on fragment definitions.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "FRAGMENT_SPREAD", + "description": "Indicates the directive is valid on fragment spreads.", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "INLINE_FRAGMENT", + "description": "Indicates the directive is valid on inline fragments.", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + } + ], + "directives": [ + { + "name": "include", + "description": "Directs the executor to include this field or fragment only when the `if` argument is true", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Included when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + }, + { + "name": "skip", + "description": "Directs the executor to skip this field or fragment when the `if`'argument is true.", + "locations": [ + "FIELD", + "FRAGMENT_SPREAD", + "INLINE_FRAGMENT" + ], + "args": [ + { + "name": "if", + "description": "Skipped when true.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "defaultValue": null + } + ] + } + ] + } +} +