В общем, когда у вас есть поле, которое может быть разрешено в один из нескольких типов, вы можете использовать Union.Если эти типы совместно используют одно или несколько полей, вы можете вместо этого использовать интерфейс.
Распространенным шаблоном, который вы видите на схемах, является идея интерфейса Node
.У вас может быть запрос на выборку узла по идентификатору, например:
type Query {
node(id: ID!): Node
}
interface Node {
id: ID!
}
type Foo implements Node {
id: ID!
foo: String!
}
type Bar implements Node {
id: ID!
bar: Int!
}
Здесь Node
может быть либо Foo
, либо Bar
, поэтому, если бы мы записали фрагментдля Node
это может выглядеть примерно так:
fragment NodeFields on Node {
id # id is part of the interface itself
... on Bar {
bar # fields specific to Bar
}
... on Foo {
foo # fields specific to Foo
}
}
Если у вас нет общих полей, вы можете использовать Союз вместо того же эффекта:
union SomeUnion = Foo | Bar
Таким образом, чтобы облегчить некоторые повторения в вашем внешнем коде, вы могли бы сделать каждый из ваших Result
типов интерфейсом или, что еще лучше, иметь один тип Result
с data
, являющимся объединением.К сожалению, ни Интерфейсы, ни Союзы не работают со Скалярами или Списками, что усложняет ситуацию, если data
должен быть Скаляр или Список для некоторых запросов.
В конце концов, однако, это, вероятно, не рекомендуетсячто вы структурируете свою схему таким образом.Существует несколько веских причин избегать такой структуры:
- GraphQL уже возвращает результат запроса в виде объекта JSON со свойствами
data
и errors
. - Возвращение ошибок внутриGraphQL
data
потребует дополнительной логики для захвата и форматирования ошибок, в отличие от возможности просто генерировать ошибку в любом месте и иметь GraphQL для обработки сообщений об ошибках для вас. - Вы не сможетечтобы фиксировать ошибки проверки, так что вы потенциально можете получить ошибки в двух местах - внутри массива
errors
и внутри data.errors
.Это также означает, что ваш клиент должен искать ошибки в двух местах, чтобы правильно обрабатывать ошибки. - GraphQL специально разработан для частичного разрешения ответа.Это означает, что даже если некоторые части ответа ошибочны и не могут быть разрешены, другие могут быть разрешены и возвращены как часть ответа.Это означает, что концепция «успешности» ответа на самом деле не применима в GraphQL.Если вам абсолютно необходимо поле
success
, было бы гораздо лучше использовать что-то вроде formatResponse
, чтобы добавить его к объекту ответа после разрешения запроса.
Это значительно упростит задачупридерживайтесь соглашения и структурируйте вашу схему следующим образом:
type Query {
login: LoginResponse
}
type LoginResponse {
token: String
user: User
}
Фактический ответ будет по-прежнему включать data
и errors
:
{
"data": {
"login": {
"token": "",
}
},
"errors": []
}
Если вам даже нужно использоватьфрагменты, вам все равно понадобится один фрагмент для каждого типа, но между фрагментами будет значительно меньше повторений.