Progetta API di query RESTful con un lungo elenco di parametri di query [chiuso]


153

Devo progettare un'API di query RESTful, che restituisca un set di oggetti basato su alcuni filtri. Il solito metodo HTTP per questo è GET. L'unico problema è che può avere almeno una dozzina di filtri e se li passiamo tutti come parametri di query, l'URL può diventare piuttosto lungo (abbastanza a lungo da essere bloccato da un firewall).

Ridurre il numero di parametri non è un'opzione.

Un'alternativa che mi viene in mente è quella di utilizzare il metodo POST sull'URI e inviare i filtri come parte del corpo POST. È questo contro essere RESTfull (effettuare una chiamata POST per interrogare i dati).

Qualcuno ha qualche suggerimento di design migliore?


2
Utilizzare nomi di parametri brevi (1 carattere, ecc.)?
Madbreaks

2
Potrebbe non essere veramente RESTful, ma penso che devi essere pratico quando si tratta di GET e POST. Se hai tante variabili da inviare e non riesci a ridurle, le POST. Non mi piace esagerare con l'URL, ma sono solo io.
Doug Dawson,

Grazie. Anche se questa domanda è chiusa, è ESATTAMENTE la domanda a cui avevo bisogno di una risposta. Sono contento che tu l'abbia chiesto.
Casey Crookston,

Risposte:


142

Ricorda che con un'API REST è tutta una questione di tuo punto di vista.

I due concetti chiave in un'API REST sono gli endpoint e le risorse (entità). In parole povere, un endpoint restituisce risorse tramite GET o accetta risorse tramite POST e PUT e così via (o una combinazione di quanto sopra).

Si accetta che con POST, i dati inviati possano o meno determinare la creazione di una nuova risorsa e dei suoi endpoint associati, che molto probabilmente non "risulteranno" sotto l'URL POST. In altre parole, quando POST invii dati da qualche parte per la gestione. L'endpoint POST non è dove normalmente è possibile trovare la risorsa.

Citando da RFC 2616 (con parti irrilevanti omesse e parti rilevanti evidenziate):

9.5 POST

Il metodo POST viene utilizzato per richiedere che il server di origine accetti l'entità racchiusa nella richiesta come nuovo subordinato della risorsa identificata dall'URI di richiesta nella riga di richiesta. POST è progettato per consentire un metodo uniforme per coprire le seguenti funzioni:

  • ...
  • Fornire un blocco di dati, come il risultato dell'invio di un modulo, a un processo di gestione dei dati;
  • ...

...

L'azione eseguita dal metodo POST potrebbe non comportare una risorsa che può essere identificata da un URI . In questo caso, 200 (OK) o 204 (Nessun contenuto) è lo stato di risposta appropriato, a seconda che la risposta includa o meno un'entità che descrive il risultato .

Se una risorsa è stata creata sul server di origine, la risposta DOVREBBE essere 201 (Creata) ...

Ci siamo abituati agli endpoint e alle risorse che rappresentano "cose" o "dati", sia esso un utente, un messaggio, un libro, qualunque sia il dominio del problema. Tuttavia, un endpoint può anche esporre una diversa risorsa, ad esempio i risultati della ricerca.

Considera il seguente esempio:

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

Questo è un tipico CRUD RIPOSO. Tuttavia cosa succede se abbiamo aggiunto:

POST /books/search

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

Non c'è nulla di non RESTOSO su questo endpoint. Accetta i dati (entità) nella forma del corpo della richiesta. Tali dati sono i criteri di ricerca - un DTO come un altro. Questo endpoint produce una risorsa (entità) in risposta alla richiesta: Risultati della ricerca . La risorsa dei risultati della ricerca è temporanea, servita immediatamente al client, senza reindirizzamento e senza essere esposta da qualche altro URL canonico.

È ancora REST, tranne per il fatto che le entità non sono libri: l'entità richiesta è un criterio di ricerca del libro e l'entità della risposta è un risultato di ricerca del libro.


Potresti suggerire alcune classi convenzioni di denominazione per il DTO?
Kwadz,

Personalmente andrei con BooksSearchCriteriaDTOe BooksSearchResultsDTO.
Amir Abiri,

quale sarebbe il miglior codice di risposta HTTP per questo caso di POST / libri / ricerca? 201 si applica ancora?
L. Holanda,

9
201 è l'opposto - implica che è stata creata una risorsa. Una risorsa che dovrebbe avere il proprio URI univoco da qualche parte. 201 è adatto quando POSTviene utilizzato per la parte C di CRUD. Vorrei andare con il semplice vecchio 200, eventualmente con 204 per risultati di ricerca vuoti.
Amir Abiri,

@AmirAbiri grazie mille.
Mohamed-Mhiri,

84

Molte persone hanno accettato la pratica secondo cui un GET con una stringa di query troppo lunga o troppo complessa (ad esempio le stringhe di query non gestiscono facilmente i dati nidificati) può essere inviato come POST, con i dati complessi / lunghi rappresentati nel corpo della richiesta.

Cerca le specifiche per POST nelle specifiche HTTP. È incredibilmente ampio. (Se vuoi navigare su una corazzata attraverso una scappatoia in REST ... usa POST.)

Perderai alcuni dei vantaggi della semantica GET ... come i tentativi automatici perché GET è idempotente, ma se riesci a convivere con quello, potrebbe essere più semplice accettare l'elaborazione di query molto lunghe o complicate con POST.

(lol digressione lunga ... Recentemente ho scoperto che secondo le specifiche HTTP, GET può contenere un corpo del documento. C'è una sezione che dice, parafrasando, "Ogni richiesta può avere un corpo del documento tranne quelli elencati in questa sezione" ... e la sezione a cui fa riferimento non ne elenca nessuna. Ho cercato e trovato un thread in cui gli autori HTTP ne parlavano, ed era intenzionale, in modo che router e simili non dovessero differenziare tra diversi messaggi. Tuttavia, in fare pratica con molti pezzi di infrastruttura lascia cadere il corpo di un OTTENERE. Quindi potresti OTTENERE con i filtri rappresentati nel corpo, come POST, ma tireresti i dadi.)


11
Vedi anche questa domanda per ulteriori discussioni su HTTP GET con body.
Ricky,

6

In poche parole: crea un POST ma sovrascrivi il metodo HTTP usando X-HTTP-Method-Override intestazione .

Richiesta reale

POST / libri

Corpo dell'entità

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

intestazioni

X-HTTP-Method-Override: GET

Sul lato server, controlla se esiste l'intestazione X-HTTP-Method-Override quindi prendi il suo valore come metodo per costruire la route verso l'endpoint finale nel back-end. Inoltre, prendi il corpo dell'entità come stringa di query. Da un punto di vista del backend, la richiesta è diventata solo un semplice GET.

In questo modo manterrai il design in armonia con i principi REST.

Modifica: so che questa soluzione era originariamente pensata per risolvere il problema del verbo PATCH in alcuni browser e server, ma funziona anche per me con il verbo GET nel caso di un URL molto lungo che è il problema descritto nella domanda.


2
Intestazioni HTTP con prefisso X X deprecate IETF: tools.ietf.org/html/rfc6648
jannis


@jannis La RFC che colleghi rimane 1.4. non fornisce raccomandazioni sulla X-rimozione esistente e 1.5. non sostituisce le specifiche esistenti. ... l' X-IMO rimarrà qui.
Jan Molnar,

-3

Se stai sviluppando in Java e JAX-RS ti consiglio di usare @QueryParam con @GET

Ho avuto la stessa domanda quando avevo bisogno di consultare un elenco.

Vedi esempio:

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();
    }
}

Pattern URI: "poc / test? Code = 1 & code = 2 & code = 3

@QueryParam convertirà automaticamente il parametro di query "orderBy = age & orderBy = name" in java.util.List automaticamente.


Sarebbe meglio se spiegassi il tuo esempio. In quale linguaggio di programmazione è scritto?
Aleks Andreev,

Ciao @AleksAndreev. Grazie per la tua opinione È andata meglio? tks
acacio.martins

Questa domanda riguarda la progettazione del servizio RESTful, non l'implementazione. Questa risposta non risponde alla domanda.
Heretic Monkey

@ user1331413 IMHO sì, ora è meglio. Grazie per il tuo impegno. Tuttavia, come ha detto Mike McCaughan, la domanda riguarda il concetto di REST, piuttosto che l'implementazione
Aleks Andreev
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.