350

Assume you have a GraphQL type and it includes many fields. How to query all the fields without writing down a long query that includes the names of all the fields?

For example, If I have these fields :

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

        ];
    }

To query all the fields usually the query is something like this:

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

But I want a way to have the same results without writing all the fields, something like this:

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

Is there a way to do this in GraphQL ??

I'm using Folkloreatelier/laravel-graphql library.

falinsky
  • 7,229
  • 3
  • 32
  • 56
BlackSigma
  • 3,505
  • 2
  • 15
  • 8
  • 20
    You're asking how to do something that GraphQL, by design, does not support. – Travis Webb Oct 25 '16 at 02:28
  • 7
    It makes sense that it isnt supported, imagine you have Student and Class objects, student have field "classes" that lists all the classes he attends, class has field "students" that lists all students that attends that class. Thats a cyclical structure. Now if you request for all students with all fields, would that also include all fields of classes returned? And those classes has students, would their fields be included too? And students have classes, ... – Buksy Apr 06 '19 at 17:20
  • 5
    I had this question and it was so that I could see what was even available to pull. Lots of GraphQL clients (e.g. GraphiQL, see https://www.gatsbyjs.org/docs/running-queries-with-graphiql/) have a schema explorer that uses the introspection to present you with what you can pull, if that's the reason behind wanting to get "everything". – James Aug 03 '20 at 20:53
  • 2
    Here is the discussion: https://github.com/graphql/graphql-spec/issues/127 – Kris Mar 03 '21 at 14:15
  • 9
    I'm sorry, can I just say GraphQL sucks? I can get all the data in 1 request instead of 2... yay...! Give me the equivalent of `SELECT *` and I'll reconsider... I'm not interested in saving 20 bytes by leaving out an email address field either. – aross Jan 04 '22 at 16:46
  • Exactly @aross, if they wanted to have validation they could let as query for some really required fields, and let the rest of them be, for example {user, email, ...} – Witold Kupś Mar 01 '22 at 04:54
  • @aross its more than just leaving out the email address in the response. its the ability to completely omit retrieving it if you don't need it. Imagine that one client needs the e-mail address and another doesn't but fetching the e-mail address adds significant latency to the response. You don't have unnecessary latency on a client that doesn't require the field that causes the latency. – user1809913 Mar 22 '22 at 21:13
  • 2
    We had to to write long reusable arrays of fields on the client so we could use select * .., so buggy.. there is no requirement GraphQL needed. Switch to tRPC, enjoy life, go outside, see some sun. – Oliver Dixon Dec 31 '22 at 18:31

6 Answers6

337

Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.

Peter Horne
  • 6,472
  • 7
  • 39
  • 50
  • 15
    Ok, and if I request some object of an unknown form from backend which I'm supposed to proxy or send back? – meandre Nov 30 '16 at 06:25
  • 54
    @meandre, the whole idea of graphql is that there is no such thing as an "unkown form". – s.meijer Dec 28 '16 at 22:16
  • 3
    @meandre, My answer below could be of use to you? – Tyrone Wilson Jan 15 '17 at 12:54
  • Isn't it the whole idea of most API query languages and protocols?, @meandre – Clijsters Feb 06 '18 at 09:58
  • 2
    interesting, it really is a different mindset when using graphql – andy mccullough Mar 21 '20 at 17:13
  • 1
    Though accurate, this is not a very useful answer. It would at least be helpful to have links and excerpts to official documentation on this topic. – ryanwebjackson Aug 10 '21 at 17:05
  • 9
    @s.meijer That's all very nice on paper. Except that in the real world, devs just request the entire thing and looking at the keys and values quickly get an idea of what's possible and what isn't. GraphQL requires much more careful consideration of the documentation in this way, sometimes for things that are relatively benign. Also very annoying is that if you need all or most properties, you still have to enumerate them *all* just to retrieve the info. It seems like inspiration taken from SQL but important parts left out. Consider `SELECT *` – aross Dec 29 '21 at 18:29
  • It's a bad and buggy 'mindset' for clients that use typed classes (95% of them). If they can give use the ability to query an object that would be great. – Oliver Dixon Dec 31 '22 at 18:34
  • another reason to not use graphql – Saylent Jul 19 '23 at 03:27
225

Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)

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

and you'll get a response like (actual field names will depend on your actual schema/type definition)

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

You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.

This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like

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

NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.

2022 Update

Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.

For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.

Mark Chackerian
  • 21,866
  • 6
  • 108
  • 99
  • Seems like one should express care about recursive types. If you went down the tree and bumped on to a type which contains itself, in some form (list, single or other..), you could be in for an infinite recursion. – Milos Grujic May 09 '19 at 13:38
  • 1
    That doesn't actually happen in my experience with this particular query -- the query itself defines the resolution depth. – Mark Chackerian May 09 '19 at 17:43
  • 2
    The above answer only allows you the query the types of fields available in a query. It doesn't return all the object fields "values", which is what the original question is about. – quantdaddy Aug 20 '19 at 21:34
  • 7
    As per the answer, you have to dynamically build a second query based on the results of the first query -- I left that as an exercise for the reader. – Mark Chackerian Aug 21 '19 at 14:48
  • And the user that will do the exercise will discover the type **UserType** has a property *fields* which is an array of objects containing *name* and *description* properties - which he already knew since that's exactly what he asked in his former query. – Gin Quin Jun 10 '21 at 11:08
  • @GinQueen I've tweaked my answer to be more clear -- the second query is to get the values of those fields from the first query, not the names of the fields. – Mark Chackerian Jun 10 '21 at 12:17
  • Can introspection be disabled in production, causing this to break? – coler-j Jul 28 '22 at 16:45
  • This is a great question -- some quick research indicates that not only is the answer yes ( see https://www.apollographql.com/blog/graphql/security/why-you-should-disable-graphql-introspection-in-production/ ) but is actually a recommended practice. I will add a caveat to my answer. – Mark Chackerian Jul 28 '22 at 18:12
68

I guess the only way to do this is by utilizing reusable fragments:

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
tommy
  • 3,517
  • 18
  • 17
  • 30
    If I did that, then still I have to write each field name "at least in the fragment", witch what I was trying to avoid, it seems that GraphQL force us to be explicit. – BlackSigma Dec 15 '15 at 12:53
  • how to add this in a POSTMan query? or jquery/UI framwork to make a stringified JSON . This graphiQL seems useless for actual development purpose. – mfaisalhyder May 15 '19 at 05:07
  • This is solely for reuse purpose. – Henok Tesfaye May 30 '19 at 11:36
  • @BlackSigma Considering [GraphQL documentation](https://graphql.org/learn/queries/#fragments), this should be the accepted as best answer – JP Ventura Oct 13 '19 at 09:35
  • 9
    @JPVentura: No my friend, there is a difference between reusability and wildcard both in concept and application. The fragment purpose is clear in the documentation " GraphQL includes reusable units called fragments." Using fragment is useful, but is not the answer for the question. – BlackSigma Oct 31 '19 at 23:27
  • It depends on if you have control over the API or not. If you do, you could create an fragment for all fields. Yes, you have to know the top-level type you are requesting, but that is reasonable, especially given the other features of GraphQL listed, like introspection. – ryanwebjackson Aug 10 '21 at 16:43
19

I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.

I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.

I defined a custom scalar type called JSON which just returns a literal JSON object.

The ruby implementation was like so (using graphql-ruby)

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

Then I used it for our objects like so

field :location, Types::JsonType

I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.

Tyrone Wilson
  • 4,328
  • 2
  • 31
  • 35
  • 4
    This is exactly what I needed, thank you. My use case is I have user-translatable strings throughout the system, and they are stored as json in the db like `{"en": "Hello", "es": "Hola"}`. And since each user can implement their own subset of languages for their use case, it doesn't make sense for the UI to query every possible subset. Your example works perfectly. – Luke Ehresman Feb 28 '18 at 21:16
  • 1
    `Otherwise it is defeating the object of GraphQL more generally speaking.` Who cares? – aross Dec 29 '21 at 18:32
  • 1
    I don't understand enough Ruby to understand what exactly you did, but I assume you wrote code to represent the foreign object, and then just send an enumeration of its properties over the line? In any case, +1 – aross Dec 29 '21 at 18:34
  • @aross basically this is a straight pass through of a hashmap. in Typescript it would be `any` or `unknown`, in golang it would be `map[string]interface{}` regardless, you are defining a custom type which just passes through whatever it receives. WRT your previous comment. Anyone who is trying to use GraphQL to shape and limit data over the wire, provide security for certain attributes or provide a Typesafe API. That's who. – Tyrone Wilson Jan 03 '22 at 12:16
  • This is a global change, right? It seems like a more local change (i.e. specific to one model's schema) could be to add a field (perhaps fields, columns, or whatever name would be more meaningful) and write a resolver that returns a json representation of all of the schema's fields. Then, the query only has to return fields. And, other developers on your team will be clued in to the unique need for that model's schema to have that representation. – Boom100100 May 16 '22 at 15:38
8

GraphQL query format was designed in order to allow:

  1. Both query and result shape be exactly the same.
  2. The server knows exactly the requested fields, thus the client downloads only essential data.

However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

Then you could query all user details by:

FetchUsers {
    users() {
        ...UserDetails
    }
}

You can also add additional fields alongside your fragment:

FetchUserById($id: ID!) {
    users(id: $id) {
        ...UserDetails
        count
    }
}
JP Ventura
  • 5,564
  • 6
  • 52
  • 69
1

Package graphql-type-json supports custom-scalars type JSON. Use it can show all the field of your json objects. Here is the link of the example in ApolloGraphql Server. https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

PokerFace
  • 811
  • 2
  • 9
  • 15