4
votes

I need to completely change field type.

Situation: I have a gateway that combines multiple services. It fetches their schemas with introspection, transforms them by adding namespaces to types (with apollo graphql-tools) and putting them in nested queries (e.g. Query: { ServiceName: { serviceQuery } }) by building a new schema with ServiceNameQuery types and setting delegate resolvers. After that I need to create cross-service links.

I have ServiceA that has a type with property related, that contains ID from TargetType from ServiceB. I need to change type of property related from ID to TargetType and add a resolver, that will fetch data from ServiceB.

Here is a real-life example: enter image description here

To do that I run visitSchema (from graphql-tools transforms) over merged schema, find the field I need, fetch TargetType from schema and change the field type and set a resolver like this:

const targetType = schema.getType('TargetType');
field.type = targetType;
field.astNode.type = targetType.astNode;
field.resolve = (parent, args, ctx, info) => {
    console.log(parent);
    return null;
  };

When I run console.log the type over resulting schema before passing it to graphql server — I see that It's type and astNode did change and they are proper.

When I run introspection — I see that type of field is proper.

But when I run a query like query { ServiceA { serviceQuery { id related { id } } } } I get error on request parse stage:

Error: Field "related" must not have a selection since type "ID" has no subfields.

GraphQL request (5:19)
4:       id
5:       related {
                     ^
6:         id

    at asErrorInstance (/.../node_modules/graphql/execution/execute.js:555:43)
    at process._tickCallback (internal/process/next_tick.js:68:7)

It event doesn't try to call serviceQuery resolver.

Where does it get the ID type of this field, when I changed the type definition? Where more I need to change it's type?

UPD Even if I create new type like this:

schema = return visitSchema(schema, {
    [VisitSchemaKind.OBJECT_TYPE](type: GraphQLObjectType) {
      if (type.getFields().relatedNews) {
        // console.log(type.getFields());
        return new GraphQLObjectType({
          name: type.name,
          fields: {
            ...fromPairs(Object.values(type.getFields()).map(({name, type, args, resolve, description}) => [name, {type, args: {}, resolve, description}])),
            relatedNews: {
              type: schema.getType('NewsArticle'),
              resolve(obj) {
                console.log('foo');
              }
            }
          }
        });
      }
      return type;
    },
  });

I keep getting this error and resolver is not triggered. If I in the same manner add a new field with different name — that works. But if name is the same — error

1

1 Answers

1
votes

Ok, I've figured out. Stitched schema keeps track of underlying stitched schemas. Changing type at top-level schema doesn't affect it so leads to internal type conflict. So type should be changed BEFORE merging