Qual è il modo corretto di eseguire un metodo di ricerca RESTful complesso?


44

Seguendo i principi REST, vorrei creare un metodo GET per la mia API che effettuasse una ricerca utilizzando alcuni criteri e restituisse i risultati al client. Il problema è che i criteri possono avere fino a 14 parametri, uno di questi è un elenco di oggetti complessi, quindi ...

  • Non so nemmeno se sia possibile codificare / decodificare questi oggetti complessi in / da parametri url.

  • Non ho calcolato quanto tempo potrebbe arrivare l'URL, ma sono sicuro che sarà abbastanza grande e forse raggiungerà il limite di lunghezza dell'URL?

Inoltre, la ricerca dovrebbe mostrare i risultati in "tempo reale", intendo, ogni volta che l'utente cambia qualcosa dal modulo di ricerca dovrebbe essere in grado di vedere i nuovi risultati senza premere alcun pulsante "cerca".

Potresti chiarirmi questi punti e quale sarebbe il tuo consiglio di creare un metodo di ricerca riposante con molti parametri?


3
A parte questo (noto che nessuna delle due risposte al momento della stesura menziona la parte in tempo reale), in genere le ricerche in tempo reale dovrebbero semplicemente inviare la richiesta aggiornata più e più volte. Ad esempio, mentre si sta digitando, devi essere l'invio di richieste per cose come search?q=t, search?q=te, search?q=teste così via. Valuta di limitare la frequenza di invio della query per evitare di danneggiare il tuo server. In alternativa, potresti anche restituire una grande quantità di informazioni e sul lato client fare il filtro. Funziona bene se l'utente inserisce ampie categorie che possono restringere notevolmente le cose.
Kat,

2
Indipendentemente dalla soluzione, assicurati di scambiare dati in un formato neutro dal punto di vista tecnologico. Quindi non usare una rappresentazione interna o sarà più difficile scrivere client per la tua API.
Kwebble,

A seconda delle tue esigenze, questa libreria potrebbe fare il lavoro: github.com/jirutka/rsql-parser . Ha un'estensione JPA se usi JPA, oppure puoi scrivere il tuo Visitatore per mapparlo all'API del tuo motore di ricerca. E puoi aggiungere il tuo operatore.
Walfrat,

Risposte:


54

Prima di leggere la mia risposta, vorrei dire che sono d'accordo con @Neil. Dobbiamo scegliere le nostre battaglie. Di solito vogliamo fare del nostro meglio, ma a volte c'è troppo poco spazio per la discussione e dobbiamo prendere decisioni contro la nostra volontà.

Comunque, nella risposta di Neil, mi manca ancora una cosa. Documentazione . Solo per garantire che gli sviluppatori sappiano che le richieste POST /searchsono sicure.

Detto ciò.

1. Dai la possibilità di OTTENERE

Considera GETprima l' opzione. Dai un'occhiata alla lunghezza massima di questa domanda URL . Valuta se la stringa di query più lunga è più lunga di 2000 caratteri. In caso contrario, e non ti aspetti che lo sia, vai con GET. Potrebbe sembrare brutto, ma almeno puoi aggiungere l'URL ai segnalibri e, ovviamente, ha tutti i vantaggi derivati ​​dalla semantica del metodo (idempotenza, sicurezza e memorizzazione nella cache)

1.1 Prova a codificare la stringa di query

Ad esempio, nella base 64. Anche javascript supporta la codifica base 64 .

Funziona così:

  1. Crea il JSON con tutti i filtri e normalizzalo.
  2. Analizzalo su stringa
  3. Codificalo
  4. Invia il JSON codificato come parametro di richiesta ( /search?q=SGVsbG8gV29ybGQh....).
  5. Sul lato server, decodifica il parametro q .
  6. Deserializza la stringa JSON

In precedenza, crea la stringa JSON più lunga possibile, codificala e prendine la lunghezza. Valuta se la stringa codificata si adatta all'URL. Ho implementato il seguente frammento su Fiddle.js per testarlo. (Spero che funzioni ancora) 1

I codifiche Base 64 sono deterministici e reversibili, quindi non c'è possibilità di collisioni.

Con le query codificate, potremmo anche salvare le ricerche nel DB, aggiungere l'URL ai segnalibri, condividere i collegamenti, ecc. E, naturalmente, non dobbiamo scappare / annullare il escape della stringa.

1.2 Prova con gli alias

Leggendo questo blog su come progettare le API REST, ho ricordato un'altra alternativa. Alias ​​per query comuni .

Trovo che questi siano interessanti per i prossimi motivi

  • Ridurre la lunghezza della stringa di query. Rende l'API più pulita e intuitiva

    GET / ticket /? Status = chiuso e chiuso At = xxx vs GET / biglietti / recentemente chiuso /

  • Combinabile con più alias o più parametri di richiesta.

    OTTIENI / biglietti /? Stato = chiuso e chiuso At = xxx e entro = 30 minuti vs OTTIENI / biglietti / recentemente chiusi /? Entro = 30 minuti

  • Siamo in grado di combinare alias con stringhe di query codificate

    GET / ticket /? Status = chiuso e chiuso At = xxx e entro = 30 minuti vs GET / ticket / recentemente chiuso /? Q = SGVsbG8g ...


1: ho usato JSON, ma potremmo usare altri formati non appena possiamo deserializzarlo sul lato server.


2
Questo è sia pratico che corretto. Vale anche la pena notare che la maggior parte dei linguaggi di programmazione rende banale la trasformazione di un hash in una stringa di query, quindi iniziare con un'azione GET è molto semplice.
Aluan Haddad,

1
Amo Spring stackoverflow.com/questions/16942193/… Non posso credere che abbia funzionato al primo tentativo: D. Per quanto riguarda la lunghezza dell'URL, è inferiore a 1k, sebbene sia ancora necessario ripetere le specifiche.
anat0lius,

Quindi, vai con GET. Per semplicità. Con Spring MVC, puoi ottenere la stessa mappatura con GET. Cerca il WebArgumentResolver di Spring ;-)
Laiv

Base64 gonfia la dimensione del carico utile di circa 4/3. Mentre urlencoding può renderlo 3/1 per caratteri speciali, le query con caratteri per lo più sicuri manterranno le stesse dimensioni. C'è qualche altro motivo per usare base64?
villasv

Non proprio. Non mi piacciono gli URL (non) di escape. La sovraccarico del payload è il compromesso qui. Deve comunque rientrare nelle dimensioni massime di GET per richiesta. Ecco perché ho creato lo snippet. Per l'utente di provare. Quando ho scritto la risposta, ho dato la priorità alla semantica web sui dettagli di implementazione. Il punto centrale della risposta è "continua a provare con GET". Trova la tua strada o usa uno di questi che condivido con te.
Laiv

13

Se tutto ciò che hai è un martello, tutto sembra un chiodo. Sembra che il problema qui sia che stai cercando di trasformare una pagina di ricerca in una RESTful, e questo non sembra essere uno schema comune da risolvere per il design RESTful.

Basta andare con una richiesta POST con parametri forniti dall'utente al fine di ottenere le informazioni richieste dal back-end. Presumo che tu non debba fare altro che eseguire una ricerca, quindi non c'è alcuna possibilità che tu debba inserire questa pagina. Aggiungi una / ricerca alla fine del tuo URL in modo da non rischiare di incorrere in conflitti con la tua pagina / utenti che sarebbe RESTful.


2
@LiLou_: per questo requisito, ci sono solo due possibilità realistiche: 1. Leggi tutti i dati sul tuo front-end e fai il filtro lì. Ciò potrebbe essere proibitivo nella quantità richiesta di memoria. 2. Effettuare una nuova richiesta al server per ogni modifica dei criteri di ricerca. Non importa se si tratta di una richiesta POST o GET, ma la latenza della rete coinvolta potrebbe essere dirompente per il senso dell'utente di aggiornamenti "in tempo reale".
Bart van Ingen Schenau,

2
Concordo di non essere d'accordo, POST significa qualcos'altro semanticamente. Suggerirei di andare con GET e passare tutti i dati del filtro nel parametro query ora se ci sono troppi parametri, allora è un errore a livello di applicazione.
CodeYogi,

2
@CodeYogi a volte il cliente non ti dà spazio per discusioni. Ho implementato pagine di visualizzazione in stile Excel con 40-50 colonne ognuna con il proprio filtro. E ordinabile ovviamente. Comunque, è ancora possibile con GET ma potrebbe non sembrare troppo di moda
Laiv

1
@Laiv in tal caso è necessario discutere seriamente perché POST è pensato per cambiare lo stato del server. I casi d'uso come questo non sono eccezionali, quindi dovrebbero essere curati senza hack.
CodeYogi,

2
In questi casi, la documentazione è un must. Ho discusso seriamente con i clienti sull'usabilità delle loro applicazioni. Successivamente ho dimostrato di avere ragione perché l'utente finale era d'accordo con me. Tuttavia, a volte devi scegliere le tue battaglie.
Laiv

0

Dipende completamente da quale sia il tuo modello API: come nessuno o come verbo.

Se l'API è nessuna, potresti voler ottenere un elenco di oggetti come segue:

GET: /api/v1/objects

In questo caso devi inviare i dati come parametri di richiesta. Quindi devi descrivere i tuoi parametri come un elenco semplice di valori-chiave:

GET: /api/v1/objects

key1 : val1
key2.key1 : val 21
key2.key2 : val 22
....

Alcune piattaforme supportano il risolutore di parametri personalizzato (ad esempio Spring MVC), e puoi convertire i parametri in un oggetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.