Schema Introspection

Specification

Introspecting a schema produces an executable schema. Queries can be executed against this schema normally.

Create and introspect a schema

        public IntrospectSchemaFacts()
        {
            var builder = new SchemaBuilder();

            builder.Interface("Interface", out var interface1,
                    "Description")
                .Connections(connect => connect
                    .Field(interface1, ScalarFieldName, ScalarType.Int));

            builder.Object(ObjectTypeName, out var type1,
                    "Description",
                    new[] {interface1})
                .Connections(connect => connect
                    .Field(type1, ScalarFieldName, ScalarType.NonNullInt,
                        "Description",
                        args: args => args.Arg("arg1", ScalarType.Float, 1d, "Description")));

            builder.Object($"{ObjectTypeName}2", out var type2,
                    "Description")
                .Connections(connect => connect
                    .Field(type2, ScalarFieldName, new List(ScalarType.Int)));


            var union = new UnionType(
                "Union",
                new[] {type1, type2},
                "Description");

            builder.Include(union);

            var enum1 = new EnumType(
                "Enum",
                new EnumValues
                {
                    {"value1", "Description"},
                    {"value2", "Description", null, "Deprecated"}
                },
                "Description");

            builder.Include(enum1);

            builder.InputObject("InputObject", out var inputObject,
                    "Description")
                .Connections(connect => connect
                    .InputField(inputObject, "field1", ScalarType.Boolean, true, "Description"));

            builder.Query(out var query)
                .Connections(connect => connect
                    .Field(query, "object", type1)
                    .Field(query, "union", union)
                    .Field(query, "enum", enum1)
                    .Field(query, "listOfObjects", new List(type2))
                    .Field(query, "nonNullObject", new NonNull(type1))
                    .Field(query, "inputObjectArg", ScalarType.NonNullBoolean,
                        args: args => args.Arg("arg1", inputObject, default, "With inputObject arg")));

            builder.Mutation(out var mutation);
            builder.Subscription(out var subscription);

            var sourceSchema = builder.Build();
            _introspectionSchema = Introspect.Schema(sourceSchema);
        }

Combination of the source schema and the introspection schema can be used to provide the normal executable schema with introspection support.


        public ISchema CreateSchema(Starwars starwars)
        {
            var schema = StarwarsSchema.Create();
            var resolvers = StarwarsResolvers.BuildResolvers(starwars);
            var executable = SchemaTools.MakeExecutableSchemaWithIntrospection(
                schema,
                resolvers);

            return executable;
        }

Type Kinds

Scalar


        [Fact]
        public async Task Type_ScalarType()
        {
            /* Given */
            var query = @"{ 
                            __type(name: ""Int"") {
                                kind
                                name
                                description
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""name"": ""Int"",
                      ""description"": ""The `Int` scalar type represents non-fractional signed whole numeric values"",
                      ""kind"": ""SCALAR""
                    }
                  }
                }");
        }

Object type


        [Fact]
        public async Task Type_ObjectType()
        {
            /* Given */
            var query = @"{ 
                            __type(name: ""Object"") {
                                kind
                                name
                                description
                                fields { name }
                                interfaces { name }
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""interfaces"": [
                        {
                          ""name"": ""Interface""
                        }
                      ],
                      ""fields"": [
                        {
                          ""name"": ""int""
                        }
                      ],
                      ""kind"": ""OBJECT"",
                      ""description"": ""Description"",
                      ""name"": ""Object""
                    }
                  }
                }");
        }

Union type


        [Fact]
        public async Task Type_UnionType()
        {
            /* Given */
            var query = @"{ 
                            __type(name: ""Union"") {
                                kind
                                name
                                description
                                possibleTypes { name }
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""kind"": ""UNION"",
                      ""description"": ""Description"",
                      ""possibleTypes"": [
                        {
                          ""name"": ""Object""
                        },
                        {
                          ""name"": ""Object2""
                        }
                      ],
                      ""name"": ""Union""
                    }
                  }
                }");
        }

Interface type


        [Fact]
        public async Task Type_InterfaceType()
        {
            /* Given */
            var query = @"{ 
                            __type(name: ""Interface"") {
                                kind
                                name
                                description
                                fields { name }
                                possibleTypes { name }
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""possibleTypes"": [
                        {
                          ""name"": ""Object""
                        }
                      ],
                      ""name"": ""Interface"",
                      ""kind"": ""INTERFACE"",
                      ""fields"": [
                        {
                          ""name"": ""int""
                        }
                      ],
                      ""description"": ""Description""
                    }
                  }
                }");
        }

Enum type


        [Fact]
        public async Task Type_EnumType()
        {
            /* Given */
            //todo(pekka): separate enumValues testing to own test
            var query = @"{ 
                            __type(name: ""Enum"") {
                                kind
                                name
                                description
                                enumValues { 
                                  name
                                  description
                                  isDeprecated
                                  deprecationReason
                                }
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""description"": ""Description"",
                      ""name"": ""Enum"",
                      ""enumValues"": [
                        {
                          ""description"": ""Description"",
                          ""name"": ""VALUE1"",
                          ""isDeprecated"": false,
                          ""deprecationReason"": null
                        }
                      ],
                      ""kind"": ""ENUM""
                    }
                  }
                }");
        }

Input object


        [Fact]
        public async Task Type_InputObjectType()
        {
            /* Given */
            var query = @"{ 
                            __type(name: ""InputObject"") {
                                kind
                                name
                                description
                            }
                        }";

            /* When */
            var result = await QueryAsync(query);

            /* Then */
            result.ShouldMatchJson(
                @"{
                  ""data"": {
                    ""__type"": {
                      ""name"": ""InputObject"",
                      ""description"": ""Description"",
                      ""kind"": ""INPUT_OBJECT""
                    }
                  }
                }");
        }