Ответ 1
К сожалению, то, что вы хотели бы сделать, невозможно. GraphQL требует, чтобы вы явно указывали, какие поля вы хотели бы вернуть из своего запроса.
Предположим, что у вас есть тип GraphQL и он включает в себя множество полей. Как запросить все поля без записи длинного запроса, который включает имена всех полей?
Например, если у меня есть эти поля:
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
Для запроса всех полей обычно запрос выглядит примерно так:
FetchUsers{users(id:"2"){id,username,count}}
Но я хочу получить одинаковые результаты, не записывая все поля, например:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Есть ли способ сделать это в GraphQL?
Я использую библиотеку Folkloreatelier/laravel-graphql.
К сожалению, то, что вы хотели бы сделать, невозможно. GraphQL требует, чтобы вы явно указывали, какие поля вы хотели бы вернуть из своего запроса.
Да, вы можете сделать это, используя самоанализ. Сделайте запрос GraphQL похожим (для типа UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
и вы получите ответ наподобие (фактические имена полей будут зависеть от вашей фактической схемы/определения типа)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
Затем вы можете прочитать этот список полей в вашем клиенте и динамически создать второй запрос GraphQL, чтобы получить все эти поля.
Это зависит от того, знаете ли вы имя типа, для которого вы хотите получить поля - если вы не знаете тип, вы можете собрать все типы и поля вместе, используя интроспекцию, например
{
__schema {
types {
name
fields {
name
description
}
}
}
}
ВНИМАНИЕ: это данные GraphQL по проводам - вы сами можете выяснить, как читать и писать с вашим реальным клиентом. Ваша javascript-библиотека graphQL уже может использовать интроспекцию в некоторой степени, например, команда apollo codegen использует интроспекцию для генерации типов.
Я предполагаю, что единственный способ сделать это - использовать повторно используемые фрагменты:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
Я столкнулся с этой же проблемой, когда мне нужно было загружать данные о местоположении, которые я сериализовал в базе данных из API google places. В общем, я бы хотел, чтобы все это работало с картами, но я не хотел указывать все поля каждый раз.
Я работал в Ruby, поэтому я не могу дать вам реализацию PHP, но принцип должен быть одинаков.
Я определил собственный скалярный тип, называемый JSON, который просто возвращает литеральный объект JSON.
Реализация ruby была подобна (используя graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Затем я использовал его для наших объектов так:
field :location, Types::JsonType
Я бы использовал это очень экономно, хотя, используя его только там, где вы знаете, что вам всегда нужен весь объект JSON (как и в моем случае). В противном случае он, вообще говоря, побеждает объект GraphQL.
Формат запроса GraphQL разработан для того, чтобы:
Однако, согласно документации GraphQL, вы можете создавать фрагменты, чтобы сделать наборы выбора более пригодными для повторного использования:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Затем вы можете запросить все данные пользователя:
FetchUsers {
users() {
...UserDetails
}
}
Вы также можете добавить дополнительные поля рядом с вашим фрагментом:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}