Query adalah cara membaca data di GraphQL: kamu menulis field yang kamu mau, bertingkat sesuai hubungan datanya, dan server menjawab dengan JSON yang susunannya sama. Bayangin menitip catatan belanja ke teman: "Di toko buku, buku nomor 1: judul dan harga. Dari penulisnya: namanya saja." Teman pulang membawa catatan yang sama, tiap baris sudah terisi, gak ada tambahan yang gak kamu tulis.
🧪 Tebakan cepat: Kamu butuh judul buku 1 dan buku 2 dalam satu query, jadi kamu tulis
book(id: 1) { title }lalubook(id: 2) { title }. Apa yang terjadi? Jawabannya ada di bagian "Alias: field yang sama dua kali".
Memilih field: selection set
Semua contoh memakai schema Toko Buku dari pelajaran sebelumnya. Query paling sederhana:
{
book(id: 1) {
title
price
}
}
{ "data": { "book": { "title": "Laskar Pelangi", "price": 89000 } } }
- Kurung kurawal terluar adalah operation. Tanpa kata di depannya, artinya query (
query { ... }sama saja). book(id: 1)adalah field diQuery, dengan argumentid.- Isi kurung kurawal setelah
bookdisebut selection set: daftar field yang dipilih dari buku itu. - Yang dikirim cuma
titledanprice.id,stock,status, danauthorgak ikut karena gak diminta.
Hasilnya 58 byte. Bandingkan dengan GET /books/1 di REST yang selalu mengirim lima field (72 byte). Kalau cuma minta title, jawabannya tinggal 44 byte. Itu keuntungan utama memilih field: data yang gak dibutuhkan gak ikut terkirim, dan ini paling terasa di jaringan seluler.
Aturannya sama di schema mana pun: { user(id: 1) { name email } } mengembalikan name dan email dari user dengan id 1, gak lebih.
Dua aturan selection set:
- Field ber-type object (
author,book) wajib punya selection set.authorsendirian ditolak. - Field scalar (
title,price) gak boleh punya selection set:title { text }ditolak denganField "title" must not have a selection since type "String!" has no subfields.
Field bersarang
Field object bisa diisi field object lagi, sedalam yang schema izinkan. Penulis nomor 1 beserta bukunya:
{
author(id: 1) {
name
books {
title
price
}
}
}
{
"data": {
"author": {
"name": "Andrea Hirata",
"books": [{ "title": "Laskar Pelangi", "price": 89000 }]
}
}
}
books adalah list ([Book!]!), jadi hasilnya array, dan selection set-nya berlaku untuk tiap buku di dalamnya.
Argument
Argument adalah nilai yang kamu kirim ke sebuah field, ditulis di dalam kurung setelah namanya. Field apa menerima argument apa, schema yang menentukan:
{
books(status: IN_STOCK) {
title
stock
}
}
{ "data": { "books": [{ "title": "Laskar Pelangi", "stock": 12 }, { "title": "Cantik Itu Luka", "stock": 5 }] } }
status: IN_STOCKadalah nilai enum, ditulis tanpa kutip. String pakai kutip:"Laskar Pelangi". Angka tanpa kutip:89000.- Argument yang wajib (
id: ID!dibook) harus dikirim.{ book { title } }ditolak:Argument "Query.book(id:)" of type "ID!" is required, but it was not provided. - Argument yang gak ada di schema ditolak:
book(isbn: "9789793062792")menghasilkanUnknown argument "isbn" on field "Query.book".
Alias: field yang sama dua kali
Dua book dengan argument berbeda di satu query akan berebut key yang sama di response, yaitu "book":
{
book(id: 1) {
title
}
book(id: 2) {
title
}
}
Server menolaknya:
{
"errors": [
{
"message": "Fields \"book\" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.",
"locations": [{ "line": 2, "column": 3 }, { "line": 5, "column": 3 }]
}
]
}
Itu jawaban tebakannya: seluruh query ditolak, gak ada data. Solusinya alias, nama lain untuk key di response, ditulis namaBaru: field:
{
laskar: book(id: 1) {
title
}
bumi: book(id: 2) {
title
stock
}
}
{
"data": {
"laskar": { "title": "Laskar Pelangi" },
"bumi": { "title": "Bumi Manusia", "stock": 0 }
}
}
Alias cuma mengganti nama key di response. Field yang dijalankan tetap book, dan tiap alias boleh memilih field yang berbeda.
__typename: nama type-nya
Tiap object punya field bawaan __typename yang berisi nama type-nya di schema. Field ini gak perlu ditulis di schema:
{
book(id: 1) {
__typename
title
author {
__typename
name
}
}
}
{ "data": { "book": { "__typename": "Book", "title": "Laskar Pelangi", "author": { "__typename": "Author", "name": "Andrea Hirata" } } } }
Ini berguna kalau satu field bisa berisi beberapa type (union dan interface), dan dipakai library seperti Apollo Client untuk menyimpan cache per type.
Field yang gak ada di schema
Field yang gak ada ditolak sebelum apa pun dijalankan. Kalau namanya mirip field yang ada, server memberi saran:
titel→Cannot query field "titel" on type "Book". Did you mean "title"?isbn→Cannot query field "isbn" on type "Book".(gak ada yang mirip, jadi gak ada saran)
⚠️ Jebakan yang sering ketemu
- Object tanpa selection set, atau scalar dengan selection set.
authorharusauthor { name }, dantitlecukuptitle. - Field yang sama dua kali tanpa alias. Beda argument berarti konflik. Kasih alias:
laskar: book(id: 1). - Enum dikutip.
books(status: "IN_STOCK")ditolak. TulisIN_STOCKtanpa kutip. - Mengira query bisa minta "semua field". GraphQL gak punya
*seperti SQL. Field yang mau diterima harus ditulis satu per satu.
📌 Nama operation dan urutan field
Operation boleh diberi nama: query BukuDetail { book(id: 1) { title } }. Hasilnya sama, tapi namanya muncul di log server dan devtools, jadi gampang dicari. Kalau satu dokumen berisi lebih dari satu operation, tiap operation wajib bernama, dan request harus menyebut mana yang dijalankan lewat operationName. Tanpa itu, server menjawab Must provide operation name if query contains multiple operations.
Urutan key di response mengikuti urutan field di query: { book(id: 1) { price title } } menjawab { "price": 89000, "title": "Laskar Pelangi" }. Nilai yang berubah-ubah, seperti id dari input pengguna, dikirim lewat variable, dibahas di pelajaran "Variables & Fragments".
TL;DR: Query membaca data: tulis field yang kamu mau, dan response-nya punya susunan yang sama, cuma berisi field itu (title saja = 44 byte, lawan 72 byte untuk /books/1). Field object wajib punya selection set { ... }, field scalar gak boleh. Field bisa bersarang (author { books { title } }), dan list menghasilkan array. Argument ditulis di kurung: wajib kalau bertanda !, dan cuma yang ada di schema. Dua field yang sama dengan argument berbeda butuh alias (laskar: book(id: 1)), kalau gak, seluruh query ditolak. __typename memberi nama type. Field yang gak ada ditolak, kadang dengan saran Did you mean.