API REST: un modo corretto di gestire gli elementi non CRUD con REST

3

Quindi, ci sono molte volte in cui devo fare cose con la mia API REST che sembrano fuori dai confini di REST. In questo caso particolare ho bisogno di avere un endpoint che controlli se un membro è idoneo per la formazione gratuita o meno.

Potrei aggiungere queste informazioni all'endpoint di lettura, ma ciò significa che verrà restituito a ogni chiamata letta. Questa volta va bene, ma cosa succede quando ci sono 100 assegni e ora restituiamo 100 campi che sono necessari solo in determinati momenti? Diventa solo gonfio.

Non mi dispiacerebbe creare un endpoint come / member / {id} / eligibleForFreeTraining e restituire un vero o falso ma che non è CRUD o REST.

Dove si collocano questi tipi di chiamate in un'API REST'ish?

    
posta Bill Garrison 01.07.2016 - 22:03
fonte

3 risposte

6

Aggiungilo alla risorsa. Se si finisce con così tante di queste domande "questa promozione speciale si applicano" che la risorsa finisce per essere enorme, dividerle in risorse correlate. Ad esempio, GET /member/{id}/promotions . Piuttosto che fare affidamento sulla struttura dell'URL, potresti anche provare a utilizzare Link Headers per comunicare tramite la risorsa /member/{id} dove le promozioni si trovano o tutte le promozioni si trovano in una raccolta di /promotions di livello superiore che può essere filtrata dal membro (ad esempio /promotions?member=/member/{id} ).

In generale, quando hai correlato informazioni aggiuntive che sono utili solo in determinati contesti, rappresentano una risorsa separata che le parti interessate possono raggiungere dalla prima risorsa. Inoltre, non pensare "Ho bisogno di controllo X", pensa "Ho bisogno di una risorsa che rappresenta il risultato del controllo di X". La risorsa /member/{id}/promotions rappresenta il server che controlla quali promozioni si applicano a un membro specifico e te le consegna. Il server esegue il controllo e la logica. Il client richiede solo risorse.

    
risposta data 01.07.2016 - 22:08
fonte
1

I wouldn't mind making an endpoint like /member/{id}/eligibleForFreeTraining and just return a true or false but that is not CRUD or REST.

C'è un precedente per quello; per esempio: link

I could possibly add this information onto the Read endpoint but that means that its going to get returned on every read call. This is fine this time, but what happens when there are 100 checks and now we return 100 fields that are only needed at certain times? It just gets bloated.

Una risposta è che puoi avere rappresentazioni multiple, con livelli diversi di dettagli. Il modo RESTful per farlo sarebbe avere diversi tipi di media che descrivono le diverse rappresentazioni.

Ad esempio, Apis per Sun Cloud definisce un numero di diverse rappresentazioni JSON, identificate da distinti < a href="https://en.wikipedia.org/wiki/Media_type#Vendor_tree"> tipi di media del fornitore .

È sempre stato consentito implementare risorse con più di una rappresentazione del tipo di supporto e nulla nelle "regole" ti impedisce di avere più di una rappresentazione con lo stesso suffisso del tipo di supporto.

La richiesta del client per la risorsa specificherà il tipo di supporto appropriato e il server lo offrirebbe, se disponibile.

Il modo RESTful di comunicare sui tipi di media disponibili è di annunciare la loro disponibilità tramite i controlli hypermedia. In altre parole, oltre a fornire al client un collegamento che specifica il tipo di supporto "standard" per la risorsa, fornisci collegamenti alternativi che può utilizzare in altre circostanze.

EDIT consentito, ma non necessariamente incoraggiato.

We encourage resource owners to only use true content negotiation (without redirects) when the only difference between formats is mechanical in nature.

- Fielding, 2006

Ciò favorirebbe, come ha osservato Jack nei commenti, utilizzando una risorsa logica diversa per le diverse rappresentazioni che si desidera supportare.

Detto questo, è probabilmente opportuno sottolineare che in un'applicazione REST (vale a dire, se l'API fornisce un protocollo), non è necessario comunicare al client lo stato del flag, ma utilizzare lo stato del flag per determinare se includere o meno collegamenti ad altre risorse nella rappresentazione della risorsa che si invia al client.

Per il tuo esempio, ciò significherebbe includere un link "Iscriviti a formazione gratuita" ai membri idonei e trattenerlo quando i membri non sono idonei, con la consapevolezza che il cliente agisce solo sui link che sono stati forniti al client come parte dello stato dell'applicazione.

    
risposta data 02.07.2016 - 00:56
fonte
1

I wouldn't mind making an endpoint like /member/{id}/eligibleForFreeTraining and just return a true or false but that is not CRUD or REST.

REST non è CRUD.

REST è il trasferimento dello stato rappresentativo. Stai trasferendo lo stato delle risorse tra il client e il server. Ciò che il client o il server fanno con queste rappresentazioni è all'altezza. A livello di comunicazione REST il protocollo non è interessato alle azioni che il client o il server eseguiranno sulla rappresentazione una volta ottenuto. Questa non è la preoccupazione di HTTP.

Le risorse sono un livello di astrazione tutto da soli, non devono essere mappati su alcun modello di dati interno sul server, né i verbi HTTP (GET, POST, PUT, DELETE ecc.) devono mappare ai comandi CRUD su il tuo modello di dati. Sul tuo server potresti avere una tabella di database e 20 risorse esposte al client. O quando il tuo cliente mette una rappresentazione su un server il server potrebbe memorizzarlo in un database, in 20 database, in un file flat, in memoria. HTTP non interessa.

Potresti usare un framework web come Rails che fondamentalmente non ottiene questo punto, ma non dare per scontato che questo sia il modo giusto per farlo solo perché un framework lo fa in questo modo. Puoi avere tutte le risorse esposte nell'interfaccia HTTP che ritieni siano necessarie.

This is fine this time, but what happens when there are 100 checks and now we return 100 fields that are only needed at certain times? It just gets bloated.

A meno che tu non abbia una buona ragione per preoccupartene (ad es. la tua risorsa ha dimensioni di megabyte), non preoccuparti di questo. È prematura l'ottimizzazione per creare uno schema URL per quel caso d'uso specifico. Da un punto di vista pratico, farà poca differenza nel trasferimento dei dati se la risorsa Membro ha 5 campi di 100 campi

È molto più facile dire che questo è l'URL della risorsa, usalo per quello che vuoi. Il cliente potrebbe aver bisogno solo del nome del membro. Potrebbe semplicemente aver bisogno dell'età del membro. Potrebbe non interessarsi al nome o all'età del membro che potrebbe voler vedere se è gratuito per la formazione.

Aumenta enormemente la complessità del tuo sistema se provi a creare endpoint URL per ogni caso di utilizzo del motivo per cui il cliente potrebbe aver bisogno dei dati. È molto più facile dire semplicemente al cliente "Ecco la risorsa, avere a disposizione" e lasciare che il cliente decida cosa vuole da quella risorsa.

    
risposta data 05.07.2016 - 11:50
fonte

Leggi altre domande sui tag