Bagaimana cara menanyakan semua bidang tipe GraphQL tanpa menulis kueri yang panjang?

130

Asumsikan Anda memiliki tipe GraphQL dan itu mencakup banyak bidang. Bagaimana cara menanyakan semua bidang tanpa menuliskan kueri panjang yang menyertakan nama semua bidang?

Misalnya, Jika saya memiliki bidang ini:

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

        ];
    }

Untuk query semua field biasanya querynya seperti ini:

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

Tetapi saya ingin cara mendapatkan hasil yang sama tanpa menulis semua bidang, seperti ini:

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

Apakah ada cara untuk melakukan ini di GraphQL ??

Saya menggunakan perpustakaan Folkloreatelier / laravel-graphql .

BlackSigma
sumber
4
Anda bertanya bagaimana melakukan sesuatu yang tidak didukung oleh GraphQL.
Travis Webb
12
Ketik saja 40 kolom sesuatu dan harap Anda tidak salah ketik :)
Ska
32
Wow, saya baru mulai di GraphQL, dan ini adalah WTF yang serius.
pengguna949300
1
Masuk akal bahwa ini tidak didukung, bayangkan Anda memiliki objek Siswa dan Kelas, siswa memiliki "kelas" bidang yang mencantumkan semua kelas yang dia hadiri, kelas memiliki bidang "siswa" yang mencantumkan semua siswa yang menghadiri kelas itu. Itu adalah struktur siklus. Sekarang jika Anda meminta semua siswa dengan semua bidang, apakah itu juga mencakup semua bidang kelas yang dikembalikan? Dan kelas-kelas itu memiliki siswa, apakah bidangnya juga akan dimasukkan? Dan siswa memiliki kelas, ...
Buksy
Saya punya pertanyaan ini dan itu agar saya bisa melihat apa yang bahkan tersedia untuk ditarik. Banyak klien GraphQL (misalnya GraphiQL, lihat gatsbyjs.org/docs/running-queries-with-graphiql ) memiliki penjelajah skema yang menggunakan introspeksi untuk menyajikan apa yang dapat Anda tarik, jika itu alasan di balik keinginan untuk mendapatkan "segalanya ".
James

Jawaban:

120

Sayangnya apa yang ingin Anda lakukan tidak memungkinkan. GraphQL mengharuskan Anda untuk secara eksplisit menentukan bidang mana yang ingin Anda kembalikan dari kueri Anda.

Peter Horne
sumber
5
Oke, dan jika saya meminta beberapa objek dengan bentuk yang tidak diketahui dari backend yang seharusnya saya proxy atau kirim kembali?
berliku
19
@ Meandre, keseluruhan gagasan graphql adalah bahwa tidak ada yang namanya "bentuk tidak dikenal".
s.meijer
2
@meandre, Jawaban saya di bawah ini dapat berguna bagi Anda?
Tyrone Wilson
Bukankah itu ide keseluruhan dari kebanyakan bahasa dan protokol kueri API ?, @meandre
Clijsters
menarik, itu benar-benar pola pikir yang berbeda saat menggunakan graphql
andy mccullough
91

Ya, Anda dapat melakukan ini dengan menggunakan introspeksi . Buat kueri GraphQL seperti (untuk tipe UserType )

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

dan Anda akan mendapatkan respons seperti (nama bidang yang sebenarnya akan bergantung pada definisi skema / jenis Anda yang sebenarnya)

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

Anda kemudian dapat membaca daftar bidang ini di klien Anda dan secara dinamis membuat kueri GraphQL kedua untuk mendapatkan semua bidang ini.

Ini bergantung pada Anda mengetahui nama tipe yang ingin Anda dapatkan bidangnya - jika Anda tidak tahu tipenya, Anda bisa mendapatkan semua tipe dan bidang bersama-sama menggunakan introspeksi seperti

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

CATATAN: ini adalah data GraphQL over-the-wire - Anda sendiri yang mengetahui cara membaca dan menulis dengan klien Anda yang sebenarnya. Pustaka javascript graphQL Anda mungkin sudah menggunakan introspeksi dalam beberapa kapasitas, misalnya perintah apollo codegen menggunakan introspeksi untuk menghasilkan tipe.

Mark Chackerian
sumber
Sepertinya seseorang harus mengungkapkan perhatian tentang tipe rekursif. Jika Anda turun ke bawah pohon dan menemukan jenis yang berisi dirinya sendiri, dalam beberapa bentuk (daftar, tunggal atau lainnya ..), Anda bisa berada dalam rekursi tak terbatas.
Milos Grujic
Itu sebenarnya tidak terjadi dalam pengalaman saya dengan kueri khusus ini - kueri itu sendiri menentukan kedalaman resolusi.
Mark Chackerian
Jawaban di atas hanya memungkinkan Anda menanyakan jenis bidang yang tersedia dalam kueri. Itu tidak mengembalikan semua bidang objek "nilai", yang merupakan pertanyaan awal tentang apa.
quantdaddy
4
Sesuai jawabannya, Anda harus secara dinamis membangun kueri kedua berdasarkan hasil kueri pertama - saya tinggalkan itu sebagai latihan untuk pembaca.
Mark Chackerian
39

Saya kira satu-satunya cara untuk melakukan ini adalah dengan memanfaatkan fragmen yang dapat digunakan kembali:

fragment UserFragment on Users {
    id
    username
    count
} 

FetchUsers {
    users(id: "2") {
        ...UserFragment
    }
}
tommy
sumber
19
Jika saya melakukan itu, maka saya masih harus menulis setiap nama bidang "setidaknya dalam fragmen", penyihir apa yang saya coba hindari, tampaknya GraphQL memaksa kami untuk bersikap eksplisit.
BlackSigma
bagaimana cara menambahkan ini dalam permintaan POST? atau jquery / UI framwork untuk membuat JSON yang dirangkai. GraphiQL ini tampaknya tidak berguna untuk tujuan pengembangan sebenarnya.
mfaisalhyder
Ini semata-mata untuk tujuan penggunaan kembali.
Henok Tesfaye
@BlackSigma Mempertimbangkan dokumentasi GraphQL , ini harus diterima sebagai jawaban terbaik
JP Ventura
4
@JPVentura: Tidak sobat, ada perbedaan antara reusability dan wildcard baik dalam konsep maupun aplikasinya. Tujuan fragmen jelas dalam dokumentasi "GraphQL menyertakan unit yang dapat digunakan kembali yang disebut fragmen." Menggunakan fragmen memang berguna, tapi bukan jawaban untuk pertanyaannya.
BlackSigma
11

Saya menghadapi masalah yang sama ini ketika saya perlu memuat data lokasi yang telah saya serialkan ke dalam database dari Google Places API. Umumnya saya ingin semuanya sehingga berfungsi dengan peta tetapi saya tidak ingin menentukan semua bidang setiap saat.

Saya bekerja di Ruby jadi saya tidak bisa memberi Anda implementasi PHP tetapi prinsipnya harus sama.

Saya mendefinisikan jenis skalar khusus yang disebut JSON yang hanya mengembalikan objek JSON literal.

Implementasi ruby ​​seperti itu (menggunakan graphql-ruby)

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

Kemudian saya menggunakannya untuk objek kami seperti itu

field :location, Types::JsonType

Saya akan menggunakan ini dengan sangat hemat, menggunakannya hanya di tempat Anda tahu Anda selalu membutuhkan seluruh objek JSON (seperti yang saya lakukan dalam kasus saya). Jika tidak, itu mengalahkan objek GraphQL secara lebih umum.

Tyrone Wilson
sumber
1
Inilah yang saya butuhkan, terima kasih. Kasus penggunaan saya adalah saya memiliki string yang dapat diterjemahkan pengguna di seluruh sistem, dan disimpan sebagai json di db like {"en": "Hello", "es": "Hola"}. Dan karena setiap pengguna dapat mengimplementasikan subset bahasanya sendiri untuk kasus penggunaannya, tidak masuk akal bagi UI untuk menanyakan setiap subset yang mungkin. Teladan Anda bekerja dengan sempurna.
Luke Ehresman
2

Format kueri GraphQL dirancang untuk memungkinkan:

  1. Bentuk kueri dan hasil sama persis .
  2. Server tahu persis bidang yang diminta, sehingga klien hanya mengunduh data penting.

Namun, menurut dokumentasi GraphQL , Anda dapat membuat fragmen untuk membuat set pilihan lebih dapat digunakan kembali:

# Only most used selection properties

fragment UserDetails on User {
    id,
    username
} 

Kemudian Anda dapat menanyakan semua detail pengguna dengan:

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

Anda juga dapat menambahkan kolom tambahan di samping fragmen Anda :

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