Skip to content

Schema Validation problems in Schema Generated by getExecutableSchema #198

@shamin2021

Description

@shamin2021

Describe the bug
When I use orchestrator and merge two subgraphs with Apollo Federation Directives as given below ,

String inventorySchema = "type Product @key(fields: \"upc\") @extends {\n" +
                "    upc: String! @external\n" +
                "    weight: Int @external\n" +
                "    price: Int @external\n" +
                "    inStock: Boolean\n" +
                "    shippingEstimate: Int @requires(fields: \"price weight\")\n" +
                "}";
String productSchema = "type Query {\n" +
      "    topProducts(first: Int = 5): [Product]\n" +
      "    productB (upc : String!): Product\n" +
      "}\n" +
      "\n" +
      "type Product @key(fields: \"upc\") {\n" +
      "    upc: String!\n" +
      "    name: String\n" +
      "    price: Int\n" +
      "    weight: Int\n" +
      "}\n";
String reviewSchema = "type Review @key(fields: \"id\") {\n" +
      "    id: ID!\n" +
      "    body: String\n" +
      "    product: Product @resolver(field:\"productB\", arguments: [{name : \"upc\", value: \"UPC001\"}])\n" +
      "}\n" +
      "\n" +
      "type User @key(fields: \"id\") @extends {\n" +
      "    id: ID! @external\n" +
      "    username: String @external\n" +
      "    reviews: [Review]\n" +
      "}\n" +
      "\n" +
      "type Product @key(fields: \"upc\") @extends {\n" +
      "    upc: String! @external\n" +
      "    reviews: [Review]\n" +
      "}\n" +
      "\n" +
      "# ================================\n" +
      "# define this as built-in directive\n" +
      "directive @resolver(field: String!, arguments: [ResolverArgument!]) on FIELD_DEFINITION\n" +
      "\n" +
      "# define this as built-in type\n" +
      "input ResolverArgument {\n" +
      "    name : String!\n" +
      "    value : String!\n" +
      "}";
String userSchema = "type Query {\n" +
      "    me: User\n" +
      "}\n" +
      "\n" +
      "type User @key(fields: \"id\") {\n" +
      "    id: ID!\n" +
      "    name: String\n" +
      "    username: String\n" +
      "}";

// Creating providers for your GraphQL services
GenericProvider inventoryService = new GenericProvider("http://localhost:8084/graphql", httpClient,
      inventorySchema, "inventory");
GenericProvider productService = new GenericProvider("http://localhost:8081/graphql", httpClient,
      productSchema, "product");
GenericProvider reviewService = new GenericProvider("http://localhost:8083/graphql", httpClient,
      reviewSchema, "review");
GenericProvider accountService = new GenericProvider("http://localhost:8082/graphql", httpClient,
      userSchema, "user");


RuntimeGraph runtimeGraph = SchemaStitcher.newBuilder()
      .service(accountService)
      .service(productService)
      .service(inventoryService)
      .service(reviewService)
      .build()
      .stitchGraph();

The stitched Schema when output through

String printSchema = new SchemaPrinter().print(runtimeGraph.getExecutableSchema());
 System.out.println(printSchema);

produces the output

"Directs the executor to include this field or fragment only when the `if` argument is true"
directive @include(
    "Included when true."
    if: Boolean!
  ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

"Directs the executor to skip this field or fragment when the `if`'argument is true."
directive @skip(
    "Skipped when true."
    if: Boolean!
  ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @provides(fields: String!) on FIELD_DEFINITION

"Exposes a URL that specifies the behaviour of this scalar."
directive @specifiedBy(
    "The URL that specifies the behaviour of this scalar."
    url: String!
  ) on SCALAR

directive @extends on OBJECT | INTERFACE

directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE

directive @key(fields: _FieldSet) repeatable on OBJECT | INTERFACE

directive @requires(fields: _FieldSet!) on FIELD_DEFINITION

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

directive @external on FIELD_DEFINITION

"[product]"
type Product {
  inStock: Boolean
  name: String
  price: Int
  reviews: [Review]
  shippingEstimate: Int
  upc: String!
  weight: Int
}

"[]"
type Query {
  _namespace: String
  me: User
  productB(upc: String!): Product
  topProducts(first: Int = 5): [Product]
}

"[review]"
type Review @key(fields : "id") {
  body: String
  id: ID!
  product: Product @resolver(arguments : [{name : "upc", value : "UPC001"}], field : "productB")
}

"[user]"
type User {
  id: ID!
  name: String
  reviews: [Review]
  username: String
}

"A selection set"
scalar _FieldSet

"[review]"
input ResolverArgument {
  name: String!
  value: String!
}

When this is parsed

SchemaParser parser = new SchemaParser();
        TypeDefinitionRegistry typeDefinitionRegistry = parser.parse(Paths.get("src/main/resources/supergraph.graphqls").toFile());
        RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().build();
        GraphQLSchema federatedSchema = Federation.transform(typeDefinitionRegistry, runtimeWiring)
                .build();
        System.out.println(federatedSchema);

There are multiple issues that arise as below ,

SchemaProblem{errors=['product' [@50:3] tried to use an undeclared directive 'resolver']}

SchemaProblem{errors=['include' type [@28:1] tried to redefine existing directive 'include' type [@1:1], 'skip' type [@30:1] tried to redefine existing directive 'skip' type [@6:1]]}

When I remove the duplicate entries for @include and @Skip and add the
directive @resolver(field: String!, arguments: [ResolverArgument!]) on FIELD_DEFINITION

the validation is successful

Can you please let me know how this can be fixed.

I further want to know if this stitched graph can be considered and treated as a supergraph similar to the one in APOLLO Federation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions