Permettere al cliente di selezionare i dati da restituire tramite l'interfaccia REST

2

Ho un servizio di riposo che è essenzialmente un proxy per una varietà di altri servizi. Quindi se chiamo

GET /users/{id}

Otterrà il proprio profilo utente, nonché la cronologia degli ordini e le informazioni di contatto, ecc. tutti provenienti da vari servizi e li aggregherà in un unico oggetto. Il mio problema è che ogni chiamata a un servizio diverso ha il potenziale di aggiungere tempo alla richiesta originale, quindi preferiremmo non ottenere TUTTI i dati TUTTO il tempo se un particolare cliente non si preoccupa di tutti i pezzi.

Una soluzione a cui sono arrivato è di fare qualcosa del genere:

GET /users/{id}?includeOrders=true&includeX=true&includeY=true...

Funziona e mi consente di fare solo ciò di cui ho bisogno, ma è ingombrante. Abbiamo aggiunto abbastanza fonti di dati differenti che ci sono troppi parametri per quello stile che possono essere utili. Potrei fare qualcosa di simile con un singolo intero e una maschera di bit o qualcosa del genere, ma questo rende solo più difficile da leggere e non sembra molto Riposo.

Potrei suddividerlo in più chiamate, quindi dovrebbero chiamare /users/{id}/orders e /users/{id}/profile separatamente, ma questo tipo di sconfigge lo scopo di un proxy aggregante, il cui scopo è quello di semplificare i lavori dei clienti.

Ci sono dei buoni schemi che possono aiutarmi a restituire un numero sufficiente di dati per ciascun cliente, senza rendere troppo difficile per loro filtrare e selezionare ciò che vogliono?

    
posta captncraig 27.11.2012 - 23:43
fonte

2 risposte

2

Come Aaron McIver ha già notato, un'architettura RESTful è principalmente pensata per lasciare che i clienti chiedono di volere (segregazione del servizio). Dovrebbe essere il tuo cliente (una pagina Web tradizionale, una pagina AJAX, un client WS senza GUI) per decidere quali fonti di informazioni desidera utilizzare e chiamare i server corrispondenti. Dovrebbe essere il tuo cliente a raccogliere dati, organizzarli e visualizzarli all'utente finale.

Non c'è niente di sbagliato nell'avere uno o più server proxy di convenienza che aggregano i dati, quando questi dati sono comunemente usati in questo modo aggregato, ma questo dovrebbe essere considerato solo questo: un metodo di convenienza, non il modo standard per andare. La ragione di ciò è ciò che stai sperimentando ora: l'interfaccia esterna (il lato per l'utente finale) subisce un'esplosione di complessità combinatoria e diventa rapidamente non controllabile.

Quindi dovresti lasciare che il tuo cliente decida se vuole interrogare uno o più server di dati aggregati o le origini dati originali. Devi lasciare il cliente per assemblare i dati e visualizzarli. Tieni presente che puoi avere più di un server proxy, se questo ha senso nel tuo caso.

Metti da parte questo, considera anche che puoi fare un buon uso della cache e delle tabelle temporanee ("viste" del database) per fornire al server proxy dati pronti per l'uso, parzialmente digeriti.

    
risposta data 28.11.2012 - 09:31
fonte
2

Suggerisco di restituire il tuo sottoinsieme minimo di dati con link agli altri dati correlati.

Se attualmente hai qualcosa di simile al seguente:

<user>
    <id>1</id>
    <defects>
        <defect id="100" ... />
        <defect id="101" ... />
        <defect id="102" ... />
    </defects>
    <stories>
        <story id="10" ... />
        <story id="11" ... />
    </stories>
</user>

Puoi trasformarlo in:

<user>
    <id>1</id>
    <defects>
        <link rel="defects" href="http://example.org/users/1/defects">
    </defects>
    <stories>
        <link rel="stories" href="http://example.org/users/1/stories">
    </stories>
</user>

Quindi il tuo cliente potrebbe seguire i link per ottenere i dati che gli interessano.

In alternativa , puoi trattare le opzioni come una singola sotto-risorsa degli utenti e, in base a come sei in grado di rispondere a determinate richieste, è possibile farlo in un unico metodo.

Per continuare il mio esempio, potresti accettare i seguenti URI:

GET /users/{id}/defects
GET /users/{id}/stories
GET /users/{id}/defects_stories
GET /users/{id}/stories_defects

In primavera potremmo realizzare ciò con qualcosa come:

@RequestMapping(value = "/users/{id}/{options}", method = RequestMethod.GET)
public @ResponseBody String get(@PathVariable Long addressId, @PathVariable String options) {
    // parse options, retrieve data, etc
    return "your xml";
}

Sulla base dei tuoi commenti aggiuntivi, questo potrebbe essere l'approccio migliore, se puoi gestirlo senza aggiungere troppa complessità. Eviterei il suggerimento di Robert Harvey di usare parametri true / false separati da barre, perché abusa del significato gerarchico degli URI; in più è persino meno leggibile della tua attuale soluzione.

In definitiva, non c'è nulla in REST contro l'utilizzo di parametri URL (poiché REST non è specifico per HTTP); vedi questa domanda SO correlata sui parametri URL & REST.

    
risposta data 28.11.2012 - 00:10
fonte

Leggi altre domande sui tag