長いクエリを作成せずにすべてのGraphQLタイプのフィールドをクエリする方法は?


130

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ライブラリを使用しています。


4
設計上、GraphQLでサポートされていない処理を行う方法を尋ねています。
Travis Webb

12
これらの40の「something」フィールドを入力して、タイプミスをしないようにしてください:)
Ska

32
うわー、私はGraphQLを始めたばかりで、これは深刻なWTFです。
user949300

1
サポートされていないことは理にかなっています。StudentオブジェクトとClassオブジェクトがあり、studentには彼が出席するすべてのクラスをリストするフィールド「classes」があり、クラスにはそのクラスに出席するすべての学生をリストするフィールド「students」があります。それは循環構造です。ここで、すべてのフィールドを持つすべての学生を要求すると、返されるクラスのすべてのフィールドも含まれますか?そしてそれらのクラスには学生がいます、彼らの分野も含まれますか?そして学生はクラスを持っています...
ブクシ

回答:


120

残念ながら、あなたがやりたいことはできません。GraphQLでは、クエリから返すフィールドを明示的に指定する必要があります。


5
わかりました、そして私がプロキシまたは送り返すことになっている未知の形式のオブジェクトをバックエンドから要求した場合?
meandre

19
@ meandre、graphqlの全体的な考え方は、「未知の形式」などは存在しないということです。
s.meijer

2
@meandre、以下の私の答えはあなたにとって役に立ちますか?
タイロンウィルソン

ほとんどのAPIクエリ言語とプロトコルのアイデア全体ではないですか?、@ meandre
Clijsters

興味深いことに、graphqlを使用する場合、これは実際には別の考え方です
andy mccullough

91

はい、イントロスペクションを使用してこれを行うことができます。次のような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. ...)
      ]
    }
  }
}

次に、クライアントでこのフィールドのリストを読み取り、2番目のGraphQLクエリを動的に作成して、これらのフィールドをすべて取得できます。

これは、フィールドを取得するタイプの名前を知っていることに依存しています。タイプがわからない場合は、次のようなイントロスペクションを使用してすべてのタイプとフィールドを一緒に取得できます。

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

注:これは有線のGraphQLデータです。実際のクライアントで読み書きする方法を理解するのは、あなた自身です。graphQL javascriptライブラリは、ある程度のイントロスペクションをすでに採用している場合があります。たとえば、apollo codegenコマンドは、イントロスペクションを使用して型を生成します。


再帰型については注意を払う必要があるようです。ツリーを下って、なんらかの形(リスト、単一など)でそれ自体を含む型にぶつかった場合、無限の再帰が発生する可能性があります。
ミロスグルジック

これは、この特定のクエリでの私の経験では実際には起こりません。クエリ自体が解決の深さを定義します。
Mark Chackerian、

上記の回答では、クエリで使用できるフィールドのタイプのみをクエリに許可します。すべてのオブジェクトフィールド「値」を返すわけではありません。これは、元の質問に関するものです。
quantdaddy

4
答えに従って、最初のクエリの結果に基づいて2番目のクエリを動的に作成する必要があります-これは読者のための演習として残しました。
Mark Chackerian、

39

これを行う唯一の方法は、再利用可能なフラグメントを利用することだと思います。

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}

19
私がそれをした場合、それでも私が避けようとしていたことを「少なくともフラグメントで」各フィールド名を書く必要があります、それはGraphQLが私たちを明示的にするように強制しているようです。
BlackSigma

これをPOSTManクエリに追加する方法 またはjquery / UIフレームワークで文字列化されたJSONを作成します。このgraphiQLは実際の開発目的には役に立たないようです。
mfaisalhyder

これは再利用のみを目的としています。
Henok Tesfaye

@BlackSigma GraphQLドキュメントを考慮すると、これはベストアンサーとして受け入れられるはずです
JP Ventura

4
@JPVentura:いいえ、私の友達ではありません。再利用性とワイルドカードには、コンセプトとアプリケーションの両方に違いがあります。フラグメントの目的は、「GraphQLにはフラグメントと呼ばれる再利用可能なユニットが含まれている」というドキュメントで明確です。フラグメントの使用は便利ですが、質問に対する答えではありません。
BlackSigma

11

GoogleプレイスAPIからデータベースにシリアル化した位置データをロードする必要があるときに、この同じ問題に直面しました。一般に、マップ全体で機能するように全体を望みますが、毎回すべてのフィールドを指定する必要はありませんでした。

私は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としてdbのように格納されてい{"en": "Hello", "es": "Hola"}ます。また、各ユーザーは、ユースケースに応じて独自の言語のサブセットを実装できるため、UIがすべての可能なサブセットをクエリすることは意味がありません。あなたの例は完璧に動作します。
ルークエーレスマン2018

2

GraphQLクエリ形式は、以下を可能にするために設計されました。

  1. クエリと結果の形状はどちらもまったく同じです。
  2. サーバーは要求されたフィールドを正確に認識しているため、クライアント重要なデータのみをダウンロードします。

ただし、GraphQLのドキュメントによれば、選択セットを再利用しやすくするためにフラグメントを作成することができます。

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

次に、次の方法ですべてのユーザーの詳細を照会できます。

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

フラグメントの横にフィールドを追加することもできます

FetchUserById($id: ID!) {
    users(id: $id) {
        ...UserDetails
        count
    }
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.