У меня есть проблемы с написанием API в graphql.
Каждый ответ в моем api должен выглядеть примерно одинаково. Итак, в идеале это был бы тип graphql:
type Response {
success
data {
... always different
}
errors {
path
message
}
}
Но потому что поле данных здесь всегда другое. У каждой мутации / запроса должен быть свой тип ответа (если я правильно понимаю graphql).
Итак, для входа в систему это тип, который я создаю с помощью функции-преобразователя:
type LoginResponse {
success
data {
user
token
}
errors {
path
message
}
}
Теперь в моем интерфейсе я хочу использовать следующий фрагмент, потому что эти свойства всегда присутствуют в каждом ответе.
fragment Response on LoginResponse {
success
errors {
path
message
}
}
Итак, проблема, с которой я сталкиваюсь, уже показана здесь, с фрагментом, который вы также определяете его родительским типом. Поэтому мне нужно создать столько отдельных фрагментов, сколько отдельных типов ответов.
Кто-то, возможно, уже боролся с этим, или есть лучшая практика для этого, я не вижу


В общем, если у вас есть поле, которое может разрешаться в один из нескольких типов, вы можете использовать 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 вместо этого с тем же эффектом:
union SomeUnion = Foo | Bar
Итак, чтобы облегчить некоторые повторения в вашем внешнем коде, вы можете сделать каждый из ваших типов Result интерфейсом или, что еще лучше, иметь один тип Result, где data является объединением. К сожалению, ни интерфейсы, ни объединения не работают со скалярами или списками, что усложняет ситуацию, если data должен быть скаляром или списком для некоторых запросов.
В конце концов, однако, вероятно, не рекомендуется изначально структурировать схему таким образом. Есть ряд веских причин избегать такой структуры:
data и errors.data потребует дополнительной логики для захвата и форматирования ошибок, в отличие от возможности просто выдать ошибку в любом месте и заставить GraphQL обрабатывать отчеты об ошибках за вас.errors и внутри data.errors. Это также означает, что ваш клиент должен искать ошибки в двух местах, чтобы правильно обрабатывать ошибки.success, было бы гораздо лучше использовать что-то вроде formatResponse, чтобы добавить его к объекту ответа после разрешения запроса.Это значительно упростит соблюдение соглашений и структурирует вашу схему следующим образом:
type Query {
login: LoginResponse
}
type LoginResponse {
token: String
user: User
}
Фактический ответ по-прежнему будет включать data и errors:
{
"data": {
"login": {
"token": "",
}
},
"errors": []
}
Если вам даже нужно использовать фрагменты, вам все равно понадобится по одному фрагменту для каждого типа, но будет значительно меньше повторений между фрагментами.
? Стоит отметить, что в дополнение к formatResponse вы также можете настроить ApolloServer с функцией formatError для лучшего контроля над тем, как ваши ошибки будут возвращены в ответ.
Хорошее видео о том, как обрабатывать ошибки (связанные с этим вопросом): https://thewikihow.com/video_-wRXk_QZ3Ko
Это именно то объяснение, которое я искал. Большое спасибо, чувак! Рефакторинг моих ответов и собираюсь опробовать автоматические ошибки rn. И раньше я видел профсоюзы, но не знал, что вы также можете фрагментировать «на» это.