Примечание: это очень упрощенный пример, но проблема та же.
Я пытаюсь обернуть существующую HTTP-службу /blog-posts интерфейсом GraphQL. Служба возвращает некоторые дополнительные данные в своем ответе, только если я передаю параметр запроса extra-data=true. Так,
GET /blog-posts: получает идентификатор и титулGET /blog-posts?extra-data=true: получает идентификатор, заголовок и поле extra-dataУ меня есть схема Absinthe, подобная следующей:
query do
field :blog_posts, non_null(list_of(non_null(:blog_post)))
resolve &MyAppWeb.Resolvers.Blog.posts/3
end
object :blog_post do
field :id, non_null(:id)
field :title, non_null(:string)
field :extra_data, :string,
resolve: &MyAppWeb.Resolvers.Blog.post_extra_data/3
end
Моя проблема в том, что я не знаю, как реализовать распознаватель extra_data, чтобы он не выполнял избыточный вызов /blog-posts?extra-data=true после того, как уже вызвал /blog-posts. Существует промежуточное ПО https://hexdocs.pm/absinthe/Absinthe.Middleware.Batch.html, предназначенное для решения аналогичной проблемы, N + 1 запросов, но я не вижу, как его применить в моем случае.
Какие-либо предложения?





Если это всего лишь одно дополнительное поле, вы можете передать необязательный аргумент в свой запрос:
query do
field :blog_posts, list_of(:blog_post) do
arg :extra_data, :boolean
resolve &MyAppWeb.Resolvers.Blog.posts/2
end
end
Но, если есть несколько необязательных аргументов, лучше использовать собственный input_object:
input_object :extra_input do
field :extra_a, :boolean
field :extra_b, :boolean
field :extra_c, :boolean
end
query do
field :blog_posts, list_of(:blog_post) do
arg :extra_fields, :extra_input
resolve &MyAppWeb.Resolvers.Blog.posts/2
end
end
И в вашем преобразователе вы можете получить поля запроса и построить с ними URL-адрес HTTP-запроса:
def posts(%{extra_fields: extra}, _resolution) do
# Here `extra` is a map of the optional fields requested. You can
# filter selected fields, map them to their HTTP service name and
# construct the HTTP url and query params before calling it in
# one go
end
In both cases, remove the resolver you've specified directly on the :extra_data field in your :blog_post object.
Поскольку это не самый распространенный вариант использования, вы не найдете решения, которое автоматически ™ ️ выполняет такое преобразование. Здесь правильным подходом является использование аргументов запроса.
Думаю, это обычный вариант использования. Я нашел два других сервера GraphQL, которые делают именно это (позвольте мне изучить выбранные вложенные поля в преобразователе более высокого уровня): lacinia.readthedocs.io/en/latest/resolve/… и sangria-graphql.org/learn/#projection. Думаю, я поговорю с ребятами из Absinthe о запросе функции.
Нашел! :-) Абсент уже имеет hexdocs.pm/absinthe/Absinthe.Resolution.html#project/2, который позволяет мне проверять вложенные выборки в текущем запросе. Я попробую это и напишу ответ.
Да, проект - это альтернативный подход, но он используется для проверки того, было ли запрошено определенное поле в запросе graphql. Это тоже решило бы вашу проблему.
Дайте мне знать, если вы не можете сделать это самостоятельно. Я отправлю еще один ответ с подходом Project / Resolution.
Спасибо! Раньше я не читал мелкий шрифт, project получает только подполя сразу под текущим полем в преобразователе. selects-field? Lacinia более мощный, он может ответить, использовалось ли поле в любом месте в запросе. Я сейчас копаюсь в структуре данных Resolution, чтобы попытаться сделать это вручную.
Спасибо. Я могу вернуться к аргументу запроса, но я надеялся на более идиоматическое решение GraphQL, то есть сопоставление части графика с параметром HTTP-запроса
extra-data.