Предположим, что у вас есть тип 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 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.
{"en": "Hello", "es": "Hola"}
. И поскольку каждый пользователь может реализовать свое собственное подмножество языков для своего варианта использования, для пользовательского интерфейса не имеет смысла запрашивать каждое возможное подмножество. Ваш пример работает отлично.