Комментарии 23
null\undefined
и попробуем посмотреть на мутации как на функции в языках программирования. И, вместо вашего оригинального технического решения, которое меняет состояние БД в query-запросах (причем, каждое поле в отдельном запросе к БД), можно решить задачу, например, так:# Создаем input, где все поля - опциональные
input ExampleOptionalInput {
foo: String
bar: String
}
# Создаем мутацию с доп. аргументом
type Mutation {
updateExampleOptionally(input: ExampleOptionalInput!, onlyFields: [String!]): Example
}
причем, каждое поле в отдельном запросе к БД
Для этого умные дядьки давным давно придумали unit of work — запрос к бд будет один. Я очень ответственно подхожу к вопросу лишних запросов.
Я думал о предложенном вами варианте. Но это порождает запросы с неопределенной структурой — в вашем варианте в onlyFields можно передавать что угодно. Ну или как минимум, завести какой-то Enum с перечислением всех полей доступных в данной сущности.
onlyFields: [ExampleInputField!]
В общем, этот вариант будет работать, но он мне субъективно не нравится.
Потому что у нас получается два источника истины: один — это список полей самой сущности, второй — это Enum перечисляющий поля.
Для этого умные дядьки давным давно придумали unit of work — запрос к бд будет один.
Будет одна транзакция. Запросов
UPDATE
будет несколько.Ну или как минимум, завести какой-то Enum с перечислением всех полей доступных в данной сущности.
Естественно, можно много как организовать валидацию. Основной смысл не меняется.
… но он мне субъективно не нравится.
С таким аргументом и не поспоришь :)
Будет одна транзакция. Запросов UPDATE будет несколько.
Вам нужно немного поработать с нормальной ORM(Datamapper) уровня Hibernate или Doctrine, чтобы понять, что это не так. У меня нет сил вам это доказывать.
Люди поработавшие с Doctrine в комментариях непременно меня опровергнут, если я не прав.
С таким аргументом и не поспоришь :)
Это было мнение. Аргументация была в следующем предложении
Там просто у greabock, насколько я могу припомнить, админка вся строится автоматически на уровне интроспекции сервера, по-этому всё так и сложно. Т.е. нужные унифицированные методы, которые позволяют автоматически строить интерфейс.
По-этому, подозреваю, и потребовалось уйти от красивой доменной модели и реализовать RESTful-подобную CRUD API.
medium.com/workflowgen/graphql-mutations-partial-updates-implementation-bff586bda989
Думаю, что объяснять суть макросов никому не нужно...
А лучше бы объяснил. Я вообще даже представить не могу как оно там может решить проблему кривого полиморфизма в gql.
Лично у себя в проекте я добавил директиву на поля:
type Paginator {
of: [Any!]!
}
type Example {
users: Paginator @generic(field: "of" type: "User")
}
Но работает оно через одно место, т.к. внедряется внутрь цикла компилятора, подменяя структуры, а значит всякие проверки и вывод типов может тут убиться об стену неконсистентными правилами LSP при имплементации интерфейсов.
А дальше, просто подставляем аргументы в шаблон. Полученные строки подмешиваются в исходник, и схема пересобирается еще раз. Так себе решение, но работает.
Отличный материал, спасибо! Мои пробы с GraphQL меня озадачили несколько другими вещами. Было бы интересно услышать мнение практика.
Сразу упомяну стек, на котором пробовал: nodejs + mongodb
Проблема N+1. DataLoader, конечно, её решает почти полностью, особенно с кэшированием. Но в целом у меня сложилось впечатление, что GraphQL хорошо подойдет для нормализованной реляционной базы, подменяя собой join-ы (и уменьшая стоимость абстракций с помощью DataLoader). Но вот если в проекте, например, mongodb и документы набиты подколлекциями, возникает необходимость ограничивать выборку по полям. И, если, где-то в API всё-таки надо получить к ним доступ, то нужно делать другой тип в Query, резолвер которого уже не ограничен по полям при выборе из базы (например, не использует проекцию в mongo).
Почему не заложена возможность получить набор запрошенных полей в самом резолвере? Есть способы вынимания их из аргумента info, но те что я видел, не позволяют просто понять, какие поля относятся к какой ветке и какому уровню. Или я проглядел?
Я обратил внимание на GraphQL по нескольким причинам:
- нафиг эти статусы, методы и кучу эндпоинтов
- возможность собрать несколько запросов в один на фронте
- схема и автодокументирование
- возможность завернуть в другой транспорт вместо http
Но вот реализация на бэке мне кажется не столько гибкой, как хотелось бы, если я хочу снизить стоимость абстракций.
Как вариант, городить свою версию на JSON-RPC...
В сложных случаях весьма неудобно разбирать поля в graphql-list-fields.
[Что не так с GraphQL]… И как с этим бороться