Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 356
acrogenesis Avatar asked Feb 08 '19 03:02

acrogenesis


People also ask

What is schema stitching?

Schema stitching combines multiple subschemas and creates a combined proxy layer called gateway that a client can use to make requests. This means that you can combine smaller GraphQL schemas from different modules or even different remote services into one schema called the gateway.

How do you combine schemas?

Combining schemas may be as simple as allowing a value to be validated against multiple criteria at the same time. These keywords correspond to well known boolean algebra concepts like AND, OR, XOR, and NOT.

Is schema stitching deprecated?

The docs say Schema Stitching is deprecated in favor of Apollo Federation. Of course, Federation can replace Schema Stitching in general. However, there are some cases only Schema Stitching makes sense.

Can GraphQL have multiple schemas?

Hence, we can create two separate schemas, the Admin and Public schemas, and expose them under endpoints /graphql/admin and /graphql respectively.

How to avoid schema conflicts while combining schemas?

Another strategy to avoid conflicts while combining schemas is to modify one or more of the subschemas using transforms. Transforming allows a schema to be groomed in such ways as adding namespaces, renaming types, or removing fields (to name a few) prior to stitching it into the combined gateway schema.

What is the use of schema stitching?

Schema stitching can also be used to customise an existing GraphQL API. For example: You want to extend the schema of an existing GraphQL API by adding more fields to an existing type whose data comes from another data source

What is @GraphQL schema stitching?

GraphQL Schema Stitching is the mechanism of composing multiple GraphQL schemas together into a single unified schema. This plays strongly into the concept of “back-ends for front-ends” which is building a specialised API designed specifically for the app in question.

Is it possible to connect multiple subschemes in one schema?

In theory, you could connect any schema that uses GraphQL as a subschema, but this isn't the case in practice. Federation uses custom directives to combine the subschemes into one schema.


1 Answers

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/

like image 192
Baruc Almaguer Avatar answered Nov 24 '22 06:11

Baruc Almaguer