¿Cómo consultar todos los campos de tipo GraphQL sin escribir una consulta larga?

Resuelto BlackSigma asked hace 54 años • 6 respuestas

Suponga que tiene un tipo GraphQL e incluye muchos campos. ¿Cómo consultar todos los campos sin escribir una consulta larga que incluya los nombres de todos los campos?

Por ejemplo, si tengo estos campos:

 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'
            ]

        ];
    }

Para consultar todos los campos normalmente la consulta es algo como esto:

FetchUsers{users(id:"2"){id,username,count}}

Pero quiero una manera de tener los mismos resultados sin escribir todos los campos, algo como esto:

FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}

¿Hay alguna manera de hacer esto en GraphQL?

Estoy usando la biblioteca Folkloreatelier/laravel-graphql .

BlackSigma avatar Jan 01 '70 08:01 BlackSigma
Aceptado

Lamentablemente lo que deseas hacer no es posible. GraphQL requiere que sea explícito al especificar qué campos le gustaría que se devuelvan de su consulta.

Peter Horne avatar Dec 11 '2015 15:12 Peter Horne

Sí, puedes hacer esto usando la introspección . Haga una consulta GraphQL como (para el tipo UserType )

{
   __type(name:"UserType") {
      fields {
         name
         description
      }  
   }
}

y obtendrá una respuesta como (los nombres de campo reales dependerán de su esquema/definición de tipo real)

{
  "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. ...)
      ]
    }
  }
}

Luego puede leer esta lista de campos en su cliente y crear dinámicamente una segunda consulta GraphQL para obtener los valores de estos campos.

Esto depende de que usted sepa el nombre del tipo para el que desea obtener los campos; si no conoce el tipo, puede obtener todos los tipos y campos juntos mediante introspección como

{
  __schema {
    types {
      name
      fields {
        name
        description
      }
    }
  }
}

NOTA: Estos son los datos GraphQL inalámbricos: usted debe descubrir cómo leer y escribir con su cliente real por su cuenta. Es posible que su biblioteca de JavaScript GraphQL ya emplee la introspección de alguna manera. Por ejemplo, el comando apollo codegen utiliza la introspección para generar tipos.

Actualización 2022

Dado que esta respuesta se escribió originalmente, ahora es una práctica de seguridad recomendada APAGAR la introspección en producción. Referencias: Por qué debería deshabilitar la introspección GraphQL en producción y OWASP | Probando GraphQL . Le recomiendo que considere si estos riesgos le conciernen.

Para un entorno donde la introspección está desactivada en producción, puede usarla en desarrollo como una forma de ayudar a crear una consulta estática que se usó en producción; En realidad, no podría crear una consulta dinámicamente en producción.

Mark Chackerian avatar May 31 '2017 15:05 Mark Chackerian

Supongo que la única forma de hacerlo es utilizando fragmentos reutilizables:

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
tommy avatar Dec 10 '2015 15:12 tommy

Me enfrenté al mismo problema cuando necesitaba cargar datos de ubicación que había serializado en la base de datos desde la API de Google Places. En general, me gustaría que todo funcionara con mapas, pero no quería tener que especificar todos los campos cada vez.

Estaba trabajando en Ruby, así que no puedo darte la implementación de PHP, pero el principio debería ser el mismo.

Definí un tipo escalar personalizado llamado JSON que simplemente devuelve un objeto JSON literal.

La implementación de Ruby fue así (usando Graphql-Ruby)

module Graph
  module Types
    JsonType = GraphQL::ScalarType.define do
      name "JSON"
      coerce_input -> (x) { x }
      coerce_result -> (x) { x }
    end
  end
end

Luego lo usé para nuestros objetos así.

field :location, Types::JsonType

Sin embargo, usaría esto con mucha moderación, usándolo solo cuando sepa que siempre necesita el objeto JSON completo (como lo hice en mi caso). De lo contrario, se derrotará el objeto de GraphQL en términos más generales.

Tyrone Wilson avatar Jan 15 '2017 12:01 Tyrone Wilson