Я искал GraphQL в качестве замены для некоторых моих REST API, и хотя мне кажется, что я обдумал основы и, как и большинство из того, что я вижу до сих пор, есть одна важная функция, которая, похоже, отсутствует.
Допустим, у меня есть коллекция таких вещей:
{
"id": "aaa",
"name": "Item 1",
...
}
Приложению требуется карта всех этих объектов, проиндексированных по идентификатору как таковая:
{
"allItems": {
"aaa": {
"name": "Item 1",
...
},
"aab": {
"name": "Item 2",
...
}
}
}
Каждый API, который я когда-либо писал, мог возвращать результаты в таком формате, но я изо всех сил пытаюсь найти способ сделать это с GraphQL. Я продолжаю натыкаться выпуск 101, но это больше касается неизвестных схем. В моем случае я точно знаю, что это за поля; это чисто формат вывода. Я знаю, что мог бы просто вернуть все элементы в массиве и переформатировать его на стороне клиента, но это кажется излишним, учитывая, что это никогда не требовалось в прошлом, и заставило бы GraphQL почувствовать себя шагом назад. Я не уверен, что то, что я пытаюсь сделать, невозможно, или я просто использую всю неправильную терминологию. Должен ли я продолжать копать, или GraphQL просто не подходит для моих нужд? Если это возможно, как может выглядеть запрос для получения таких данных?
Я сейчас работаю с graphql-PHP на сервере, но я открыт для концептуальных ответов более высокого уровня.
К сожалению, возвращение объектов с произвольными и динамическими ключами, как это, на самом деле не является первоклассным гражданином в GraphQL. Это не означает, что вы не можете достичь того же, но при этом вы потеряете многие из преимуществ GraphQL.
Если вы настроены на возвращение объекта с ключами идентификатора вместо возврата коллекции / списка объектов, содержащих идентификаторы, а затем выполняете преобразование на клиенте, то вы можете создать специальный GraphQLScalarType.
const GraphQLAnyObject = new GraphQLScalarType({
name: 'AnyObject',
description: 'Any JSON object. This type bypasses type checking.',
serialize: value => {
return value;
},
parseValue: value => {
return value;
},
parseLiteral: ast => {
if (ast.kind !== Kind.OBJECT) {
throw new GraphQLError("Query error: Can only parse object but got a: " + ast.kind, [ast]);
}
return ast.value;
}
});
Проблема с этим подходом состоит в том, что, поскольку это скалярный тип, вы не можете предоставить набор выбора для его запроса. НАПРИМЕР. если у вас был тип
type MyType implements Node {
id: ID!
myKeyedCollection: AnyObject
}
Тогда вы сможете только запросить его так
query {
getMyType(id: abc) {
myKeyedCollection # note there is no { ... }
}
}
Как уже говорили другие, я бы не рекомендовал это, потому что вы теряете много преимуществ GraphQL, но это показывает, что GraphQL все еще может делать почти все, что может REST. Если вы просто хотите попробовать это, мы предоставляем типы AnyObject на scaphold.io что вы можете поиграть с.
Надеюсь это поможет!
Других решений пока нет …