Are object resolvers broken with custom schema directives?

I use object resolvers and also custom schema directives, in a federated schema.

Based on this issue:

It looks to me like if you use schema directives with federation, you should expect for object resolvers to not be working?

Additionally, it looks like this issue has been around for ~6 months?

Am I crazy? Is there a workaround for this? Seems pretty strange to have core features not work for 6 months. I’m aware that object resolvers are currently undocumented, but I definitely wouldn’t expect them to just be broken with normal use-cases. As it stands, I can’t upgrade to v3 at all if these features break when working together.

3 Likes

Hey @kevin-lindsay-1, just opened an issue for this. Thanks for bringing to our attention! I plan to get to it reasonably soon (order of week(s)), but if expediency is important I’d welcome a PR!

@kevin-lindsay-1 I ended up with this quick workaround:

import { IResolvers } from '@graphql-tools/utils';
import { GraphQLSchema } from 'graphql';

const APOLLO_RESOLVE_REFERENCE_FIELD_NAME = '__resolveReference';

const APOLLO_FIELD_NAME_PREFIX = '__';

/**
 * The workaround for the bug:
 *
 * https://github.com/ardatan/graphql-tools/issues/2687
 * https://community.apollographql.com/t/are-object-resolvers-broken-with-custom-schema-directives/1578
 *
 * @param schema schema to fix '__...' resolver on
 * @param resolvers
 */
export function fixApolloResolvers(
  schema: GraphQLSchema,
  resolvers: IResolvers,
  apolloFields: string[] = [APOLLO_RESOLVE_REFERENCE_FIELD_NAME],
) {
  const apolloFieldsSet = new Set(apolloFields);

  const typeMap = schema.getTypeMap();

  for (const [name, type] of Object.entries(typeMap)) {
    const typeResolvers = resolvers[name];

    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
    if (typeResolvers) {
      const apolloResolverFieldNames = Object.keys(typeResolvers).filter(
        (fieldName) => apolloFieldsSet.has(fieldName),
      );

      for (const apolloResolverFieldName of apolloResolverFieldNames) {
        const trimmedName = apolloResolverFieldName.substring(
          APOLLO_FIELD_NAME_PREFIX.length,
        );

        const apolloResolver = (typeResolvers as any)[apolloResolverFieldName];
        (type as any)[trimmedName] = apolloResolver;
      }
    }
  }
}

Call fixApolloResolvers(...) after the transformation.

1 Like

ew, I love it!

I’ll give it a shot when I’m free, juggling over here.

nice! i’ll throw a +1 on it.