Как запросить все поля типа GraphQL без написания длинного запроса?

47

Предположим, что у вас есть тип 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.

  • 3
    Вы спрашиваете, как сделать что-то, что GraphQL не поддерживает.
  • 5
    Просто введите эти 40 полей что-то и надеюсь, что вы не сделаете опечатку :)
Показать ещё 1 комментарий
Теги:
graphql
graphql-php

4 ответа

43
Лучший ответ

К сожалению, то, что вы хотели бы сделать, невозможно. GraphQL требует, чтобы вы явно указывали, какие поля вы хотели бы вернуть из своего запроса.

  • 3
    Хорошо, а если я запрошу какой-нибудь объект неизвестной формы из бэкэнда, который я должен прокси или отправить обратно?
  • 10
    @meandre, вся идея graphql заключается в том, что не существует такой вещи, как «неизвестная форма».
Показать ещё 2 комментария
38

Да, вы можете сделать это с помощью самоанализа. Сделайте запрос 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 использует интроспекцию для генерации типов.

20

Я предполагаю, что единственный способ сделать это - использовать повторно используемые фрагменты:

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
  • 12
    Если бы я сделал это, то все равно мне пришлось бы писать каждое имя поля «хотя бы во фрагменте», что я и пытался избежать, похоже, что GraphQL заставляет нас быть явными.
6

Я столкнулся с этой же проблемой, когда мне нужно было загружать данные о местоположении, которые я сериализовал в базе данных из 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.

  • 1
    Это именно то, что мне было нужно, спасибо. Мой пример использования - у меня в системе есть переводимые пользователем строки, и они хранятся в виде json в БД, как {"en": "Hello", "es": "Hola"} . И поскольку каждый пользователь может реализовать свое собственное подмножество языков для своего варианта использования, для пользовательского интерфейса не имеет смысла запрашивать каждое возможное подмножество. Ваш пример работает отлично.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню