1 poin oleh GN⁺ 4 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • RFC 10008 mendefinisikan metode HTTP QUERY yang mengembalikan hasil setelah resource target memproses kueri secara aman dan idempoten yang dikirim dalam body permintaan
  • QUERY menggabungkan sifat safe/idempotent milik GET dengan cara pengiriman body milik POST, sehingga mengurangi URI yang panjang, biaya encoding URI, paparan di log, dan beban menjadikan setiap kombinasi kueri sebagai resource terpisah
  • Server hanya dapat memproses permintaan QUERY jika Content-Type dan body permintaannya konsisten; tipe yang tidak didukung, ketidaksesuaian body, dan kueri yang tidak dapat diproses dapat dibedakan dengan respons 4xx yang berbeda
  • Respons yang berhasil dapat memberi tahu resource hasil kueri lewat Content-Location, dan equivalent resource untuk menjalankan ulang kueri yang sama lewat Location
  • Respons QUERY dapat di-cache, tetapi cache key harus mencakup body dan metadata; di lingkungan CORS, metode ini bukan safelisted method sehingga memerlukan preflight

Pola kueri HTTP yang ingin diselesaikan oleh QUERY

  • RFC 10008 adalah dokumen Internet Standards Track yang mendefinisikan metode permintaan QUERY di HTTP
  • QUERY meminta resource target memproses body permintaan dan mengembalikan hasilnya dalam respons
  • Seperti POST, metode ini menggunakan body, tetapi didefinisikan sebagai safe dan idempotent sehingga dapat di-retry atau dijalankan ulang secara otomatis
  • Kueri GET yang ada biasanya menaruh input di URI
    • GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
  • Menaruh data kueri di URI membuat batasan makin besar saat data membesar
    • Karena melewati banyak sistem independen, sulit mengetahui batas ukuran URI yang nyata sebelumnya
    • HTTP merekomendasikan pengirim dan penerima mendukung setidaknya 8000 octets, tetapi itu tidak menjamin semua sistem di sepanjang jalur
    • Beberapa data mahal untuk di-encode menjadi URI yang valid
    • URI permintaan lebih mungkin tercatat di log atau masuk ke bookmark dibanding body permintaan
    • Jika kueri di-encode langsung ke URI, setiap kombinasi input yang mungkin diperlakukan sebagai resource terpisah

Metode yang memperjelas makna di antara GET dan POST

  • Banyak implementasi mengirim kueri lewat body POST alih-alih GET
    • POST /feed
    • Content-Type: application/x-www-form-urlencoded
    • Body: q=foo&limit=10&sort=-published
  • Dengan cara ini, tanpa pengetahuan tentang resource dan server tertentu, tidak terlihat apakah kuerinya aman dan idempoten
  • QUERY mengirim input yang sama di body permintaan, tetapi metodenya sendiri bersifat aman dan idempoten
    • QUERY /feed
    • Content-Type: application/x-www-form-urlencoded
    • Body: q=foo&limit=10&sort=-published
  • Makna eksplisit ini memudahkan penerapan fitur HTTP seperti caching dan retry otomatis
  • Server dapat memberi URI pada kueri itu sendiri atau pada hasil kueri tertentu untuk dipakai dalam permintaan GET berikutnya

Aturan inti metode QUERY

  • QUERY digunakan untuk memulai kueri di sisi server
  • GET meminta representasi dari resource yang diidentifikasi oleh URI target, sedangkan QUERY meminta dilakukannya operasi kueri dalam cakupan resource target
  • Body permintaan dan media type mendefinisikan kueri, dan origin server menentukan cakupan operasi berdasarkan resource target
  • Server harus menggagalkan permintaan jika field permintaan Content-Type tidak ada atau tidak cocok dengan body permintaan
  • Query part dari URI target ikut serta dalam identifikasi resource target, sama seperti pada semua metode HTTP
    • Apakah query part itu langsung memengaruhi hasil dan bagaimana caranya adalah perilaku khusus resource dan di luar cakupan spesifikasi ini
  • QUERY aman dari sudut pandang resource target
    • Klien tidak meminta atau mengharapkan perubahan status resource target
    • Server tetap tidak dilarang membuat resource HTTP yang dapat diakses untuk mengambil informasi tambahan
  • QUERY bersifat idempoten, sehingga dapat di-retry atau diulang bila perlu setelah kegagalan koneksi
  • Respons 200 OK menunjukkan kueri berhasil diproses dan hasilnya disertakan dalam body respons

Media type, negosiasi, dan penanganan kesalahan

  • Makna permintaan QUERY bergantung pada body permintaan dan metadata terkait seperti media type
  • Permintaan yang body dan metadatanya tidak konsisten umumnya harus ditolak dengan 4xx Client Error
  • Penanganan kesalahan berbeda tergantung di mana letak kesalahannya
    • Jika tidak ada informasi media type, permintaan salah secara definisi sehingga harus gagal dengan status 4xx seperti 400
    • Jika media type ditentukan tetapi tidak didukung resource, maka 415 Unsupported Media Type sesuai
    • Meski media type itu dikenal secara umum, jika tidak ada makna QUERY untuk resource target, itu juga termasuk kasus 415
    • Jika media type tidak cocok dengan body permintaan yang sebenarnya, server dapat mengembalikan 400 Bad Request
    • Server tidak boleh melakukan content sniffing dengan melihat body untuk menebak media type lalu menimpa nilai yang hilang atau salah
    • Jika tipe dan body cocok tetapi isi kueri itu sendiri tidak dapat diproses, dapat digunakan 422 Unprocessable Content
    • Contoh 422 adalah kueri SQL yang sintaksnya benar tetapi menunjuk ke tabel yang tidak ada
    • Jika resource tidak mendukung media type respons yang diminta klien lewat Accept, maka 406 Not Acceptable sesuai
  • Field respons Accept-Query dapat memberi tahu klien media type kueri yang didukung

equivalent resource, Content-Location, Location

  • equivalent resource adalah resource yang merepresentasikan permintaan QUERY tertentu beserta targetnya, dan merespons permintaan GET
  • Equivalent resource mempertimbangkan body permintaan dan metadata sekaligus
    • Termasuk representation metadata seperti media type dari body
  • Server dapat memberikan URI pada equivalent resource, tetapi tidak wajib
  • Respons yang berhasil dapat menyertakan identifier resource yang sesuai dengan hasil kueri lewat header Content-Location
    • Klien dapat mengirim GET ke URI yang ditunjukkan untuk mengambil hasil dari operasi kueri yang baru saja dilakukan
    • Resource itu dapat bersifat sementara
  • Respons yang berhasil dapat menyertakan URI equivalent resource dari permintaan QUERY lewat header Location
    • Klien dapat mengirim GET ke URI yang ditunjukkan untuk mengulangi operasi kueri yang sama tanpa mengirim ulang body kueri
    • URI ini juga dapat bersifat sementara
    • Jika permintaan berikutnya gagal, klien dapat mencoba lagi dengan target QUERY asli dan body yang sebelumnya dikirim

Pengalihan dan permintaan bersyarat

  • Untuk permintaan QUERY, server dapat memilih respons tidak langsung yang mengalihkan user agent ke URI lain
  • 301 Moved Permanently dan 308 Permanent Redirect menunjukkan resource target telah dipindahkan secara permanen ke URI lain yang ditunjuk Location
  • 302 Found dan 307 Temporary Redirect berarti perpindahan sementara dari resource target
  • Dalam keempat kasus itu, server menyarankan bahwa permintaan asli dapat dijalankan dengan mengirim permintaan QUERY serupa ke URI target yang baru
  • Pengecualian yang mengalihkan POST menjadi GET setelah 301 atau 302 tidak berlaku untuk permintaan QUERY
  • 303 See Other untuk QUERY menunjukkan bahwa kueri asli dapat dijalankan sebagai permintaan pengambilan biasa terhadap URI yang ditunjuk Location
    • Dalam HTTP, ini berarti mengirim permintaan GET ke URI target yang baru
  • Dalam QUERY bersyarat, selected representation sama dengan GET terhadap equivalent resource dari permintaan QUERY tersebut
  • Klien dapat meminta agar hasil kueri dikembalikan hanya jika kondisi yang ditentukan oleh header bersyarat terpenuhi

Caching dan permintaan Range

  • Respons metode QUERY dapat di-cache, dan cache dapat digunakan untuk memenuhi permintaan QUERY berikutnya
  • Cache key untuk permintaan QUERY harus mencakup body permintaan dan metadata terkait
  • Cache dapat menghapus perbedaan yang secara semantik tidak penting untuk membuat cache key
    • menghapus content encoding
    • normalisasi menurut konvensi format yang ditunjukkan oleh suffix media subtype seperti +json
    • normalisasi menurut makna body yang ditunjukkan oleh Content-Type
  • Transformasi ini hanya untuk pembuatan cache key dan tidak mengubah permintaan itu sendiri
  • Klien dapat menandai lewat direktif cache no-transform bahwa transformasi semacam ini tidak diinginkan, tetapi direktif ini bersifat advisory
  • Caching respons QUERY pada dasarnya lebih kompleks daripada GET
    • Untuk menentukan cache key, seluruh body permintaan harus dibaca
    • Jika respons QUERY memberi URI equivalent resource lewat Location, klien dapat beralih ke GET sesudahnya untuk menyederhanakan pemrosesan
  • Makna Range Request pada QUERY sama seperti pada GET
  • Satu-satunya range unit yang didefinisikan saat penulisan, yaitu Byte Range Request, bernilai kecil untuk hasil QUERY
  • Dalam banyak kasus, format kueri itu sendiri menyediakan pembatasan hasil atau pagination, seperti FETCH FIRST ... ROWS ONLY pada SQL, dan penggunaan fitur bawaan seperti itu memang diharapkan

Header respons Accept-Query

  • Header respons Accept-Query secara langsung memberi tahu bahwa resource mendukung metode QUERY dan mengidentifikasi media type format kueri yang dapat digunakan
  • Accept-Query adalah daftar media range yang menggunakan sintaks Structured Fields
  • Media range dinyatakan sebagai List Structured Header Field dari Token atau String yang berisi nilai media range tanpa parameter
  • Parameter media type dipetakan ke Structured Field Parameters
    • Pilihan antara String dan Token tidak penting secara semantik
    • Penerima dapat mengubah Token menjadi String, tetapi tidak boleh memprosesnya berbeda berdasarkan tipe yang diterima
  • Media type tidak selalu dipetakan tepat ke Token, dan bila angka di awal diizinkan maka format String harus digunakan
  • Wildcard yang didukung hanya */* atau xxxx/*
  • Urutan tipe yang tercantum dalam nilai field tidak penting
  • Nilai Accept-Query berlaku untuk semua URI di server yang berbagi path yang sama, dan query component diabaikan
  • Jika permintaan ke resource yang sama mengembalikan nilai Accept-Query yang berbeda, nilai fresh yang diterima paling baru yang digunakan
  • Contohnya sebagai berikut
    • Accept-Query: "application/jsonpath", application/sql;charset="UTF-8"
  • Accept-Query terlihat mirip dengan Accept, tetapi karena merupakan Structured Field, pemrosesannya harus mengikuti aturan Structured Fields dari RFC 9651

Pertimbangan keamanan dan CORS

  • QUERY mengikuti semua pertimbangan keamanan umum untuk metode HTTP sebagaimana didefinisikan di RFC 9110
  • QUERY dapat digunakan sebagai alternatif terhadap cara menaruh informasi permintaan di query component URI
  • Karena URI lebih mungkin tercatat di log atau diproses perantara dibanding body permintaan, QUERY dapat menjadi alasan untuk dipilih daripada GET saat kueri memuat informasi sensitif
  • Saat server membuat resource sementara yang merepresentasikan hasil QUERY dan memberinya URI, jika body permintaan asli berisi informasi sensitif yang tidak boleh tercatat di log, bagian sensitif itu tidak boleh dimasukkan ke URI tersebut
  • Jika cache menormalisasi body QUERY secara keliru atau dengan cara yang sangat berbeda dari cara resource memprosesnya, respons yang salah bisa dikembalikan sebagai false positive
  • Permintaan QUERY dari user agent yang mengimplementasikan CORS memerlukan permintaan preflight
    • QUERY tidak termasuk dalam kumpulan CORS-safelisted methods

Registrasi IANA dan pemilihan nama metode

  • IANA menambahkan metode QUERY ke HTTP Method Registry
    • Method Name: QUERY
    • Safe: yes
    • Idempotent: yes
    • Specification: RFC 10008 Section 2
  • IANA menambahkan field Accept-Query ke HTTP Field Name Registry
    • Field Name: Accept-Query
    • Status: permanent
    • Structured Type: List
  • Di HTTP Method Registry sudah ada PROPFIND, REPORT, dan SEARCH yang memiliki sifat safe dan idempotent
  • Pada tahap awal, SEARCH digunakan, tetapi nama metode finalnya menjadi QUERY
  • Alasan QUERY dipilih adalah sebagai berikut
    • Alternatif-alternatifnya menggunakan media type umum application/xml di body permintaan dan makna permintaan sepenuhnya bergantung pada body
    • Alternatif-alternatif itu semuanya berasal dari aktivitas WebDAV
    • QUERY menangkap dengan baik hubungan dengan query component pada URI

1 komentar

 
GN⁺ 4 jam lalu
Komentar Hacker News
  • Akan lebih meyakinkan kalau ada contoh motivasi yang kuat, tetapi contoh yang dipakai terlalu mudah diekspresikan dengan GET sehingga malah terasa mengaburkan
    Bahkan jika membayangkan QUERY yang memasukkan struktur filter JSON besar atau input gambar ke dalam body permintaan, tetap terasa sangat aneh bahwa body permintaan menjadi bagian dari kunci cache. Itu menciptakan kunci cache tak terbatas yang dikendalikan pengguna, dan strategi caching umum pada praktiknya hanya bisa membandingkan body permintaan per bit atau melakukan hash, jadi dalam situasi jahat cache menjadi sangat mudah di-invalidasi
    Jika membuat layanan yang memerlukan pemfilteran kompleks atau input kompleks seperti gambar, kemungkinan caching akan berada jauh dari lapisan HTTP. Misalnya, bisa memakai kunci seperti kolom data individual dari join, atau embedding yang dikunci dengan perceptual hash dari input gambar yang sudah didekode, sehingga tidak bergantung pada representasi bit yang persis sama di wire
    Saya tidak paham mengapa hal seperti ini harus dipaksakan ditangkap dengan cara umum. Menurut saya jauh lebih baik mengekspresikan semantik caching pada POST dengan header baru seperti "Vary: request-body". Itu sepenuhnya kompatibel ke belakang, dan selain untuk 0,1% kasus CDN yang mungkin merasa perilaku ini berguna, sisanya bisa saja mengabaikannya

    • Bagian query pada URI di GET juga pada kenyataannya hampir tidak punya batas, dikendalikan pengguna, dan karena merupakan bagian dari URI, ikut masuk ke kunci cache. Jadi saya kurang paham kenapa kebalikannya dianggap isu khusus
    • Jika browser ingin kunci cache yang lebih kecil, cukup simpan hash tahan tabrakan dari body. Misalnya pakai SHA-256
      Saya tidak terpikir serangan terkait caching yang tidak berlaku sama juga untuk parameter query. Kalau ingin membanjiri cache, membuat parameter query unik 30 karakter sama mudahnya dengan membuat body permintaan 30 MB
    • Tidak semua skenario penggunaan ada di internet publik, dan meskipun tidak berguna di internet publik, itu juga bukan berarti tidak bisa distandardisasi
      Secara realistis, sistem untuk internet publik akan memakai hash kriptografis sebagai kunci cache agar ukurannya selalu tetap. Kunci cache juga sudah mencakup URL yang bisa sangat panjang dan sekumpulan nilai header arbitrer
    • Gambar juga bisa dikirim sebagai body permintaan, tetapi saat ini juga sudah bisa lewat parameter query base64. Kalau sengaja mau dipakai secara aneh, standar usulan apa pun bisa disalahgunakan
      GET dengan parameter query pun sudah opak dan membuat invalidasi cache jadi mudah
    • Misalnya saya sedang membuat server MCP untuk basis data. Di ChatGPT, sebelum commit saya ingin lebih dulu melakukan dry-run POST yang nantinya di-rollback, tetapi karena keduanya sama-sama request POST yang hanya berbeda satu properti, ini sering memicu lapisan keamanan tool. Karena berbagai alasan, penyebab pastinya juga sulit di-debug
      Namun kalau menaruh QUERY di depan POST, rasanya akan lebih baik. Karena itu bukan lagi request yang sama dengan flag aman, melainkan tipe request yang berbeda
  • Saya penasaran apakah form HTML akan menambahkan dukungan QUERY
    Karena QUERY harus idempoten, ini bisa menghindari peringatan kirim ulang yang menjengkelkan saat menyegarkan halaman hasil submit form POST

    • Mendukung lebih banyak metode selain GET/POST di form HTML adalah sesuatu yang sudah diinginkan selama puluhan tahun. Kebetulan ada proposal WHATWG, jadi kalau ingin ikut menyuarakan dukungan, ke sini: https://github.com/whatwg/html/pull/11347
    • Salah satu keanehan form adalah hasil dari form POST berupa halaman yang punya lokasi (URL), tetapi tidak bisa dimuat lewat lokasi itu. Sejauh yang saya tahu, fakta bahwa halaman itu didapat dengan POST, bukan GET, tidak disimpan di tempat yang bisa dilihat pengguna atau JS, dan refresh juga berperilaku aneh
      Jika method=QUERY ditambahkan, keanehan ini hanya akan punya satu varian baru lagi
    • Ini lebih baik diselesaikan dengan pola POST-Redirect-GET
    • Lihat https://github.com/whatwg/html/issues/12594
    • Mereka belum pernah menambahkan dukungan untuk verba lain, tetapi sekarang eranya sudah berbeda jadi entah bagaimana nanti
  • Untuk yang masih ingin berpura-pura kita hidup di abad lalu: https://www.rfc-editor.org/rfc/rfc10008.txt

    • Saya rasa saya akan selamanya menyukai dokumen teks biasa yang panjang dan lengkap seperti ini. Mengingatkan pada masa indah waktu kecil membaca FAQ video game. Dalam banyak hal, ini benar-benar format informasi yang unggul
    • Pemformatannya indah. Rasanya ingin saya tiru sebagai template gaya untuk memo kerja internal. Tak lekang oleh zaman
  • “Usulan untuk menambahkan body ke request GET telah ditinjau mendalam oleh kelompok kerja IETF, tetapi pada akhirnya diputuskan untuk membuat metode QUERY yang baru. Keputusan membuat metode terpisah didorong oleh masalah interoperabilitas historis dan kepatuhan ketat terhadap definisi arsitektur inti HTTP”
    Tetapi saya sudah bertahun-tahun mengirim body permintaan dengan metode GET

    • Katanya beberapa load balancer membuang body-nya
    • Secara umum itu bukan ide bagus. Pada beberapa implementasi HTTP bahkan tidak mungkin dilakukan. fetch, misalnya, seperti itu
      https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/U...
      “GET request tidak bisa menyertakan body”
      Bisa juga menimbulkan masalah aneh karena caching transparan
  • Mengejutkan bahwa sekarang kita sudah sampai di nomor RFC 5 digit

  • Seseorang membuat taruhan ambigu soal kapan RFC 10000 akan diterbitkan, lalu penomoran melompat langsung dari 9998 ke 10008. Tidak ada yang menang
    https://manifold.markets/CollectedOverSpread/when-will-rfc-1...

  • Jadinya seperti kalau ingin menanyakan hasil pencarian dalam HTTP, pakailah metode QUERY, dan jangan tambahkan parameter query
    Namanya membingungkan. Istilah query sudah dipakai untuk merujuk ke permintaan HTTP secara umum
    Saya juga bingung hanya dari melihat judul RFC-nya

    • Dalam bidang apa istilah query dipakai untuk merujuk ke permintaan HTTP secara umum? Secara lisan orang kadang menyebut request GET sebagai query, tetapi untuk POST, PUT, DELETE jelas tidak pernah
    • Betul. Lagi pula ini juga tidak harus berupa query, bisa juga efek idempoten. Mungkin akan lebih baik kalau disebut IPOST, yaitu POST yang idempoten
      Edit: oh, ternyata QUERY dinyatakan sebagai metode “aman” tanpa efek samping demi memungkinkan caching. Saya keliru
  • Jika ini benar-benar sampai menggantikan request GET dengan query string di dunia nyata, saya sangat berharap bookmark browser mendukung pelestarian parameter permintaan

    • Rasanya mungkin tidak akan begitu. Kemungkinan lebih besar ini menggantikan tempat-tempat yang saat ini memakai POST untuk keperluan query
  • Saya tahu ini di luar cakupan RFC ini, tetapi hal bagusnya adalah ini bisa dengan mudah diperluas agar JS EventSource juga bisa dipakai untuk query AI streaming
    Karena permintaan butuh body, semua orang akhirnya memakai POST, dan hasil streaming sering memakai protokol text/event-stream di respons. Tetapi sebenarnya tidak ada perubahan state, jadi secara teknis kurang pas, dan EventSource tetap keras kepala hanya bisa memakai GET. Akibatnya banyak API mengimplementasikan ulang fungsi yang sama dengan parser sendiri

  • Saat melihat GET: Content (body) "no defined semantics", saya sempat berpikir mungkin tidak masalah mengizinkan body pada metode GET, tetapi menurut spesifikasi aslinya body GET memang harus diabaikan sepenuhnya
    Selain itu, caching juga bisa rusak jika bagian penting dari request dimasukkan ke dalam body yang dibuang

    • GET yang hanya berisi URI punya semantik mengambil representasi saat ini dari suatu resource. Ini adalah bentuk paling dasar dari hyperlink dan cukup penting bagi cara kerja web
      Jika menambahkan parameter body ke GET, dua request dengan URI yang sama tidak lagi bisa diperlakukan sebagai menunjuk hal yang sama, sehingga membongkar batasan metode ini