Ответ 1
Оба предназначены для разработки схемы с гетерогенным набором типов, и вы можете добиться одинаковой функциональности с помощью обоих, но GraphQLInterfaceType
более подходит, когда типы в основном одинаковы, но некоторые из полей различны, и GraphQLUnionType
, когда типы полностью различны и имеют совершенно разные поля.
В конечном счете, следует ли использовать тот или иной вариант в зависимости от дизайна схемы.
Для примера в реальном мире, скажем, у вас есть список блогов, но блоги с использованием фреймворка A используют имя пользователя и пароль в качестве аутентификации, а блог с использованием фреймворка B использует электронную почту и пароль. Мы проектируем его с помощью GraphQLInterfaceType
следующим образом:
const BlogType = new GraphQLInterfaceType({
name: 'Blog',
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
password: { type: new GraphQLNonNull(GraphQLString) }
},
resolveType: resolveBlogType
});
const BlogAType = new GraphQLObjectType({
name: 'BlogA',
interfaces: [Blog],
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
username: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const BlogBType = new GraphQLObjectType({
name: 'BlogB',
interfaces: [Blog],
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
email: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
function resolveBlogType(value) {
return value.username ? BlogAType : BlogBType;
}
Когда мы создаем новый блог, отправляющий username
, он создаст BlogA
.
Мы можем запросить вот так:
query MyQuery {
blogs: {
url
password
... on BlogA {
email
}
... on BlogB {
username
}
}
}
Теперь позвольте получить ту же функциональность, но используя GraphQLUnionType
, потому что мы предпочитаем использовать только один тип блога и два типа методов проверки подлинности:
const AuthAType = new GraphQLObjectType({
name: 'AuthA',
fields: {
username: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const AuthBType = new GraphQLObjectType({
name: 'AuthB',
fields: {
email: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const AuthType = new GraphQLUnionType({
name: 'Auth',
types: [AuthAType, AuthBType]
resolveType: resolveAuthType
});
const BlogType = new GraphQLInterfaceType({
name: 'Blog',
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
auth: { type: AuthType }
},
});
function resolveAuthType(value) {
return value.username ? AuthAType : AuthBType;
}
Мы можем запросить вот так:
query MyQuery {
blogs: {
url
auth {
... on AuthA {
username
password
}
... on AuthB {
email
password
}
}
}
}
Как вы можете видеть в этом примере, мы достигаем того же с интерфейсом или объединением, но один или другой может быть более уместным в зависимости от вашего дизайна схемы.
Например, скажем, вы хотите добавить структуру блога C, в которой также используется электронная почта и пароль. Вам нужно будет включить другое поле, чтобы можно было отличить его от рамки B блога в нашей функции resolveBlogType
. Добавьте поле type
. В нашем примере Союза, поскольку у нас есть только доступ к полям в Союзе, вы должны добавить type
в Союз. Если в будущем мы хотели бы добавить еще один Union с одинаковыми полями для нескольких фреймворков, нам нужно будет также добавить поле type
. Не так приятно иметь type
дублировать несколько раз в нашей схеме. Лучше было бы использовать интерфейс и иметь одно поле type
, доступное в функции resolveBlogType
всеми объектами, использующими интерфейс.