在 GraphQL 开发过程中,我们常常需要将多个 GraphQL schema 合并成一个。但是在实际情况中,我们可能会遇到一些难以处理的合并问题。本文将介绍如何解决 GraphQL Schema 合并问题。
问题描述
当我们需要将多个 GraphQL schema 合并成一个时,我们需要使用一个工具来实现。比如说,graphql-tools
提供了一个 mergeSchemas
函数来实现这个功能。下面是一个简单的示例代码:
// javascriptcn.com 代码示例 const { mergeSchemas } = require("graphql-tools"); const { makeExecutableSchema } = require("graphql-tools"); const productSchema = makeExecutableSchema({ typeDefs: ` type Product { id: ID! name: String! price: Float! } type Query { getProduct(id: ID!): Product! } `, }); const customerSchema = makeExecutableSchema({ typeDefs: ` type Customer { id: ID! name: String! email: String! } type Query { getCustomer(id: ID!): Customer! } `, }); const mergedSchema = mergeSchemas({ schemas: [productSchema, customerSchema], }); console.log(mergedSchema);
在上面的代码中,mergeSchemas
函数将 productSchema
和 customerSchema
两个 schema 合并成一个。我们可以得到一个新的 schema,其中包含了两个原先 schema 的所有类型和字段。
然而,在实际情况中,我们可能会遇到一些难以处理的问题。比如说,如果两个 schema 中有同名的类型或字段,会发生什么?
// javascriptcn.com 代码示例 const { mergeSchemas } = require("graphql-tools"); const { makeExecutableSchema } = require("graphql-tools"); const productSchema = makeExecutableSchema({ typeDefs: ` type Product { id: ID! name: String! price: Float! } type Query { getProduct(id: ID!): Product! getProducts: [Product!]! } `, }); const customerSchema = makeExecutableSchema({ typeDefs: ` type Customer { id: ID! name: String! email: String! } type Query { getCustomer(id: ID!): Customer! getCustomers: [Customer!]! } `, }); const mergedSchema = mergeSchemas({ schemas: [productSchema, customerSchema], }); console.log(mergedSchema);
在上面的代码中,productSchema
和 customerSchema
两个 schema 都定义了 Query
类型,且其对应的字段也重复定义了。当我们尝试合并这两个 schema 时会发生什么?
问题分析
在上面的例子中,如果我们尝试合并 productSchema
和 customerSchema
,会得到以下错误:
Error: Type "Query" has multiple definitions.
这个错误告诉我们,在两个 schema 中,有同名的类型或字段。这是 GraphQL schema 合并过程中常见的问题。
在 GraphQL schema 中,每个类型或字段都需要一个唯一的名称。如果两个 schema 中出现重名的情况,那么就会导致合并失败。
解决方案
为了解决这个问题,我们可以采用以下两种方法:
1. 使用自定义前缀
我们可以为每一个 schema 添加一个自定义前缀,以确保每个类型和字段都具有唯一的名称。
// javascriptcn.com 代码示例 const { mergeSchemas } = require("graphql-tools"); const { makeExecutableSchema } = require("graphql-tools"); const productSchema = makeExecutableSchema({ typeDefs: ` type Product { id: ID! name: String! price: Float! } type Query { getProduct(id: ID!): Product! getProducts: [Product!]! } `, }); const customerSchema = makeExecutableSchema({ typeDefs: ` type Customer { id: ID! name: String! email: String! } type Query { getCustomer(id: ID!): Customer! getCustomers: [Customer!]! } `, }); const transformedSchemas = [ { schema: productSchema, prefix: 'Product_' }, { schema: customerSchema, prefix: 'Customer_' } ]; const mergedSchema = mergeSchemas({ schemas: transformedSchemas.reduce((acc, { schema, prefix }) => { const transformedSchema = transformSchema(schema, [ new RenameTypes((name) => `${prefix}${name}`), ]); return [...acc, transformedSchema]; }, []), }); console.log(mergedSchema);
在上面的代码中,我们为每个 schema 添加了一个自定义前缀,以确保它们的类型和字段名称具有唯一性。在合并 schema 之前,我们使用 graphql-tools
中的 transformSchema
函数将所有 schema 中的类型名称和字段名称重命名。这样,在合并 schema 时,就不会出现重名情况了。
2. 使用自定义后缀
我们还可以为每个 schema 添加一个自定义后缀。这个方法跟添加前缀的方法很类似,只需要在合并 schema 之前,使用 graphql-tools
中的 transformSchema
函数将所有 schema 中的类型名称和字段名称添加后缀即可。
// javascriptcn.com 代码示例 const { mergeSchemas } = require("graphql-tools"); const { makeExecutableSchema } = require("graphql-tools"); const productSchema = makeExecutableSchema({ typeDefs: ` type Product { id: ID! name: String! price: Float! } type Query { getProduct(id: ID!): Product! getProducts: [Product!]! } `, }); const customerSchema = makeExecutableSchema({ typeDefs: ` type Customer { id: ID! name: String! email: String! } type Query { getCustomer(id: ID!): Customer! getCustomers: [Customer!]! } `, }); const transformedSchemas = [ { schema: productSchema, suffix: '_Product' }, { schema: customerSchema, suffix: '_Customer' } ]; const mergedSchema = mergeSchemas({ schemas: transformedSchemas.reduce((acc, { schema, suffix }) => { const transformedSchema = transformSchema(schema, [ new RenameTypes((name) => `${name}${suffix}`), ]); return [...acc, transformedSchema]; }, []), }); console.log(mergedSchema);
总结
在 GraphQL 开发过程中,我们经常需要将多个 schema 合并成一个。但是在合并 schema 的过程中,可能会出现类型或字段重名的问题。为了解决这个问题,我们可以为每个 schema 添加一个自定义前缀或后缀,以确保每个类型和字段都具有唯一的名称。在合并 schema 之前,我们使用 graphql-tools
中的 transformSchema
函数将所有 schema 中的类型名称和字段名称重命名或添加前缀/后缀。这样,就能避免类型或字段重名的问题了。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6535e4dc7d4982a6ebd9b2fb