Desain RESTful query API dengan daftar panjang parameter kueri [ditutup]

153

Saya perlu merancang API permintaan RESTful, yang mengembalikan satu set objek berdasarkan beberapa filter. Metode HTTP biasa untuk ini adalah GET. Satu-satunya masalah adalah, ia dapat memiliki setidaknya selusin filter, dan jika kita melewatkan semuanya sebagai parameter kueri, URL bisa menjadi cukup lama (cukup lama untuk diblokir oleh beberapa firewall).

Mengurangi jumlah parameter bukanlah suatu pilihan.

Salah satu alternatif yang dapat saya pikirkan adalah memanfaatkan metode POST pada URI dan mengirim filter sebagai bagian dari badan POST. Apakah ini bertentangan dengan RESTfull (Melakukan panggilan POST untuk meminta data).

Adakah yang punya saran desain yang lebih baik?

missionE46
sumber
2
Gunakan nama parameter pendek (1-char, dll)?
Madbreaks
2
Ini mungkin tidak benar-benar tenang, tetapi saya pikir Anda harus praktis ketika datang ke GET dan POS. Jika Anda memiliki banyak variabel untuk dikirim dan Anda tidak dapat menguranginya, saya akan POST. Saya tidak suka membuat URL terlalu berlebihan, tapi itu hanya saya.
Doug Dawson
Terima kasih. Meskipun pertanyaan ini sudah ditutup, ini adalah PERSIS pertanyaan yang saya butuhkan jawabannya. Saya senang Anda bertanya.
Casey Crookston

Jawaban:

142

Ingat bahwa dengan API REST, itu semua adalah pertanyaan tentang sudut pandang Anda.

Dua konsep utama dalam REST API adalah titik akhir dan sumber daya (entitas). Secara longgar, endpoint mengembalikan sumber daya melalui GET atau menerima sumber daya melalui POST dan PUT dan sebagainya (atau kombinasi dari yang di atas).

Diterima bahwa dengan POST, data yang Anda kirim dapat atau tidak dapat mengakibatkan penciptaan sumber daya baru dan titik akhir yang terkait, yang kemungkinan besar tidak akan "hidup" di bawah url POSTed. Dengan kata lain ketika Anda POST Anda mengirim data ke suatu tempat untuk penanganan. Titik akhir POST bukanlah tempat sumber daya biasanya ditemukan.

Mengutip dari RFC 2616 (dengan bagian yang tidak relevan dihilangkan, dan bagian yang relevan disorot):

9,5 POST

Metode POST digunakan untuk meminta server asal menerima entitas yang dilampirkan dalam permintaan sebagai bawahan baru dari sumber daya yang diidentifikasi oleh Request-URI di Request-Line. POST dirancang untuk memungkinkan metode yang seragam untuk mencakup fungsi-fungsi berikut:

  • ...
  • Memberikan blok data, seperti hasil pengiriman formulir, ke proses penanganan data;
  • ...

...

Tindakan yang dilakukan oleh metode POST mungkin tidak menghasilkan sumber daya yang dapat diidentifikasi oleh URI . Dalam hal ini, 200 (OK) atau 204 (Tidak Ada Konten) adalah status respons yang sesuai, tergantung pada apakah respons tersebut termasuk atau tidak entitas yang menjelaskan hasil .

Jika sumber daya telah dibuat di server asal, respons HARUS 201 (Dibuat) ...

Kami telah terbiasa dengan titik akhir dan sumber daya yang mewakili 'barang' atau 'data', baik itu pengguna, pesan, buku - apa pun yang ditentukan domain masalah. Namun, titik akhir juga dapat mengekspos sumber daya yang berbeda - misalnya hasil pencarian.

Perhatikan contoh berikut:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

Ini adalah CREST REST tipikal. Namun bagaimana jika kami menambahkan:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

Tidak ada yang tenang tentang titik akhir ini. Ia menerima data (entitas) dalam bentuk badan permintaan. Data itu adalah Kriteria Pencarian - DTO seperti yang lain. Titik akhir ini menghasilkan sumber daya (entitas) dalam menanggapi permintaan: Hasil Pencarian . Sumber daya hasil pencarian bersifat sementara, disajikan segera kepada klien, tanpa arahan ulang, dan tanpa terkena dari beberapa url kanonik lainnya.

Itu masih REST, kecuali entitas bukan buku - entitas permintaan adalah kriteria pencarian buku, dan entitas respons adalah hasil pencarian buku.

Amir Abiri
sumber
Bisakah Anda menyarankan beberapa konvensi penamaan kelas untuk DTO?
Kwadz
Secara pribadi saya akan pergi dengan BooksSearchCriteriaDTOdan BooksSearchResultsDTO.
Amir Abiri
apa yang akan menjadi kode respons HTTP terbaik untuk kasus POST / buku / pencarian ini? 201 masih berlaku?
L. Holanda
9
201 adalah sebaliknya - ini menyiratkan bahwa sumber daya telah dibuat. Sumber daya yang diharapkan memiliki URI uniknya sendiri di suatu tempat. 201 cocok ketika POSTdigunakan untuk bagian C dari CRUD. Saya akan menggunakan 200, yang mungkin opsional dengan 204 untuk hasil pencarian kosong.
Amir Abiri
@AmirAbiri terima kasih banyak.
mohamed-mhiri
84

Banyak orang telah menerima praktik bahwa GET dengan string kueri yang terlalu panjang atau terlalu rumit (mis. String kueri tidak mudah menangani data bersarang) dapat dikirim sebagai POST, dengan data kompleks / panjang terwakili dalam tubuh dari permintaan.

Cari spec untuk POST di spec HTTP. Ini sangat luas. (Jika Anda ingin berlayar kapal perang melalui celah di REST ... gunakan POST.)

Anda kehilangan beberapa manfaat dari semantik GET ... seperti coba ulang otomatis karena GET idempoten, tetapi jika Anda dapat hidup dengan itu, mungkin lebih mudah untuk hanya menerima pemrosesan pertanyaan yang sangat panjang atau rumit dengan POST.

(lol penyimpangan panjang ... Saya baru-baru ini menemukan bahwa dengan spec HTTP, GET dapat berisi badan dokumen. Ada satu bagian yang mengatakan, parafrase, "Permintaan apa pun dapat memiliki badan dokumen kecuali yang terdaftar di bagian ini" ... dan bagian yang dimaksud tidak mencantumkan apa pun. Saya mencari dan menemukan utas di mana penulis HTTP membicarakan hal itu, dan itu disengaja, sehingga router dan semacamnya tidak perlu membedakan antara pesan yang berbeda. berlatih banyak potongan infrastruktur yang menjatuhkan tubuh GET. Jadi Anda bisa MENDAPATKAN dengan filter yang terwakili dalam tubuh, seperti POST, tetapi Anda akan menggulirkan dadu.)

rampok
sumber
11
Lihat juga pertanyaan ini untuk diskusi lebih lanjut tentang HTTP GET with body.
RickyA
6

Singkatnya: Buat POST tetapi timpa metode HTTP menggunakan header X-HTTP-Method-Override .

Permintaan nyata

POST / buku

Badan entitas

{"title": "Ipsum", "year": 2017}

Tajuk

X-HTTP-Method-Override: GET

Di sisi server, periksa apakah header X-HTTP-Method-Override ada kemudian ambil nilainya sebagai metode untuk membangun rute ke titik akhir akhir di backend. Juga, ambil badan entitas sebagai string kueri. Dari sudut pandang backend, permintaan menjadi GET sederhana.

Dengan cara ini Anda menjaga desain tetap selaras dengan prinsip REST.

Sunting: Saya tahu solusi ini pada awalnya dimaksudkan untuk memecahkan masalah kata kerja PATCH di beberapa browser dan server tetapi juga berfungsi untuk saya dengan GET kata kerja dalam kasus URL yang sangat panjang yang merupakan masalah yang dijelaskan dalam pertanyaan.

Delmo
sumber
2
IETF mencabut header HTTP awalan X-: tools.ietf.org/html/rfc6648
jannis
@jannis RFC yang Anda tautkan tetap 1.4. itu tidak membuat rekomendasi untuk X-penghapusan yang ada dan 1.5. itu tidak mengesampingkan spesifikasi yang ada. ... X-akankah IMO tetap di sini.
Jan Molnar
-3

Jika Anda berkembang di Java dan JAX-RS, saya sarankan Anda menggunakan @QueryParam dengan @GET

Saya memiliki pertanyaan yang sama ketika saya perlu membaca daftar.

Lihat contoh:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

Pola URI: “poc / test? Kode = 1 & kode = 2 & kode = 3

@QueryParam akan mengonversi parameter kueri “orderBy = age & orderBy = name” menjadi java.util.List secara otomatis.

acacio.martins
sumber
Akan lebih baik jika Anda menjelaskan contoh Anda. Dalam bahasa pemrograman apa ini ditulis?
Aleks Andreev
Hai @AlexAndreev. Terima kasih atas pendapat Anda. Sudah lebih baik? tks
acacio.martins
Pertanyaan ini adalah tentang desain layanan RESTful, bukan tentang implementasinya. Jawaban ini tidak menjawab pertanyaan.
Monyet
@ user1331413 IMHO ya, sekarang lebih baik. Terima kasih atas usaha Anda .. Namun, seperti dikatakan Mike McCaughan, pertanyaannya adalah tentang konsep REST, bukan implementasi
Aleks Andreev