typescriptgraphqlapolloapollo-servergraphql-tools

Schema Stitching resolve conflict by adding prefix


So I have this two schemas

Schema1

type Permission {
    relation: Relation
}

enum Relation {
    ONE
    TWO
    THREE
}

Schema2

type Permission {
    relation: Relation
}

enum Relation {
    FOUR
    FIVE
    SIX
}  

The expect result is something similar to: (but I'm open to different ideas) The queries I would like to make after the merge are:

{
    permissions{
        relation
    }
}

And get a result like

"permissions": [
  {
    "relation": "ONE"
  },
  {
    "relation": "SIX"
  }
]

or

"permissions": [
  {
    "relation": "schema1ONE"
  },
  {
    "relation": "schema2SIX"
  }
]

And mutations like:

mutation{
  createPermission(
    relation: ONE
  ){
    relation
  }
}

mutation{
  createPermission(
    relation: SIX
  ){
    relation
  }
}

or

mutation{
  createPermission(
    relation: schema1ONE
  ){
    relation
  }
}

mutation{
  createPermission(
    relation: schema2SIX
  ){
    relation
  }
}

I'm trying using the transformSchema function on graphql-tools but can't quite figure it out correctly:

const Schema1 = await getRemoteSchema('schema1_url', 'schema1');
const Schema2 = await getRemoteSchema('schema2_url', 'schema2');

const schemas = [Schema1, Schema2]

const schema = mergeSchemas({
  schemas: schemas,
  resolvers: {}
});

getRemoteSchema definition

export const getRemoteSchema = async (uri: string, schemaName: string): Promise<GraphQLSchema> => {
  const httpLink = new HttpLink({ uri, fetch });

  const schema = await introspectSchema(httpLink);

  const executableSchema = makeRemoteExecutableSchema({
    schema,
    httpLink,
  });

  // transform schema by renaming root fields and types
  const renamedSchema = transformSchema(
    executableSchema,
    [
      new RenameTypes(name => {
        if (name == 'Relation') {
          return schemaName + name
        } else {
          return name
        }
      }),
      // new RenameRootFields((operation, name) => `${schemaName}_${name}`)
    ]
  );

  return renamedSchema;
}    

I made this glitch https://glitch.com/edit/#!/schema-stitching-conflict So it's easier to see the problem.


Solution

  • You need both RenameTypes and RenameRootFields transforms, RenameTypes to transform the typenames

    from: Permission and Relation (The colliding types),

    to: schema1_Permission, schema2_Permission

    and: schema1_Relation, schema1_Relation

    RenameRootFields to transform the Query names for those types

    from: permission(id: ID!): Permission

    to: schema1_permission(id: ID!): schema1_Permission and schema2_permission(id: ID!): schema2_Permission

    and: permissions: [Permission]

    to: schema1_permissions: [schema1_Permission] and schema2_permissions: [schema2_Permission]

    The transform would be something like:

    const {
      makeExecutableSchema,
      addMockFunctionsToSchema,
      transformSchema,
      RenameTypes,
      RenameRootFields
    } = require('graphql-tools');
    
    const schema1 = makeExecutableSchema({
      typeDefs: `
        type Permission {
          id: ID!
          text: String
          relation: Relation
        }
    
        type Query {
          permissions: [Permission]
          permission(id: ID!): Permission
        }
    
        enum Relation {
          ONE
          TWO
          THREE
        }
      `
    });
    
    addMockFunctionsToSchema({ schema: schema1 });
    
    const renamedSchema1 = transformSchema(
      schema1,
      [
        new RenameTypes(name => {
          if (name == 'Relation' || name == 'Permission') {
            return 'schema1_' + name
          } else {
            return name
          }
        }, { renameBuiltins: false, renameScalars: true }),
        new RenameRootFields((_op, name) => {
          return name.includes('ermission') ? `schema1_${name}` : name
        })
      ]
    );
    

    references: https://www.apollographql.com/docs/graphql-tools/schema-transforms/ https://www.apollographql.com/docs/graphql-tools/schema-stitching/