Rappresenta azioni (verbi) nell'URI REST


16

Ho un'operazione di stampa da eseguire per i documenti dei miei clienti. Ho bisogno di eseguire anche le altre operazioni standard, come aggiungere, aggiornare, eliminare. quindi, ho il seguente:

  • Per creare un nuovo cliente:
    URI = / customer / {id}, digitare = POST, Nome metodo = CreateCustomer ()
  • Per l'aggiornamento:
    URI: / customer / {id}, digitare = PUT, method = UpdateCstomer ()
  • Per Elimina cliente:
    URI = / cliente / {id}, digitare = ELIMINA, Nome metodo = Elimina cliente ()
  • Per Visualizza:
    URI: / customer / {id}, digitare = GET, method = GetCustomer ()

Ora, se devo stampare un documento per quel cliente, ho bisogno di una funzione di stampa. Il mio URI potrebbe essere simile al seguente: / customer / {id}, type = POST, method = PrintCustomer (). Ma ho usato quel tipo di URI e POST per CreateCustomer. Volevo che l'URI fosse simile a questo: / customer / Print / {id}, type = POST, method = PrintCustomer ().

Ma non posso avere il verbo "Stampa" nel mio URI. qual'è il miglior modo per farlo? Ho pensato a / customer / document / {id} come l'URI ... ma incontrerò lo stesso problema. Avrei le operazioni CRUD sul "documento". Quindi, ancora una volta esaurisco ciò che avrei usato per "stampare". Si prega di avvisare.


2
La stampa è di solito un'operazione sul lato client, quindi sono curioso: in che modo l'installazione è tale da richiedere l'invio di un comando a un server REST?
Shauna

2
@Shauna Non necessariamente, l'URI può essere una richiesta al server per una versione stampabile della risorsa (ovvero una vista diversa).
Evan Plaice,

1
@EvanPlaice - Abbastanza giusto, anche se questo lascia ancora l' atto di stampa al client (che, anche dopo aver recuperato una versione stampabile sul lato server, avrebbe quindi deciso su quale dispositivo stampare e inviare il comando di stampa stesso, anche se quello il comando passa a un server di stampa). Una richiesta per ottenere una versione stampabile di una risorsa sarebbe quindi logicamente ... beh ... OTTIENI.
Shauna

@Shauna L'attivazione di un processo di stampa da una sola richiesta HTTP sarebbe impossibile a causa della sicurezza del browser. Una richiesta per una versione stampabile è solo una richiesta GET ma è ancora necessario un modo per specificare che il browser deve eseguire il rendering della versione stampabile. È possibile specificare un URL diverso ma ciò violerebbe i principi di REST perché in realtà non si richiede una diversa risorsa, ma solo una diversa trasformazione della stessa risorsa. Da qui la ragione per specificare la trasformazione tramite un parametro di query e / o un tipo di contenuto.
Evan Plaice,

Non ho abbastanza rappresentante da pubblicare come risposta, ma trovo interessante che tyk.io/rest-never-crud sostenga che POST /customers/123/printsia una cosa valida da fare.
jlh

Risposte:


9

POSTnon significa "creare", significa "processo". È possibile creare una nuova risorsa inviando una richiesta adatta a una risorsa esistente (ovvero postare /customersper creare un nuovo cliente). Ma puoi anche usare POSTper compilare tutte le altre azioni che non corrispondono a un chiaro paradigma CRUD.

Nel caso della stampa, è necessario considerare l'atto di stampa come una risorsa stessa. Stai chiedendo al sistema di creare un "lavoro di stampa" per te. Questo significa che puoi avere una prints/risorsa che funge da contenitore per tutte le stampe richieste. Quando vuoi stampare qualcosa, sei POSTun documento su questa risorsa che contiene tutte le informazioni sulla stampa che vuoi creare, identificando le risorse che vuoi stampare con collegamenti ad esse.

Come documento JSON, potrebbe assomigliare a questo:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

Ovviamente, è necessario personalizzarlo per essere pertinenti a ciò che si desidera fare. La cosa fondamentale è che stai identificando altre risorse da stampare specificando il loro URL.

In risposta alla richiesta, potresti semplicemente restituire a 200 OKo a 204 No-Contente trattarlo come un processo di fuoco e dimentica. Tuttavia, se si desidera migliorarlo, è possibile restituire 201 Createde specificare l'URL del processo di stampa appena creato, ad es /prints/12345.

Un utente potrebbe quindi eseguire una ricerca GETsulla risorsa per vedere lo stato del proprio lavoro di stampa (in sospeso, in corso, ecc.) Oppure richiedere che il lavoro venga annullato emettendo un DELETE.

Una volta riformulato il problema in termini di risorse, il design RESTful dovrebbe essere naturale e offrirti l'opportunità di espandersi e migliorare in modi che potresti non aver immediatamente preso in considerazione.


2
POST di solito significa creare / inserire, mentre put di solito significa aggiornare salvare / aggiornare. Ecco come viene definito in REST anche se non è come viene normalmente utilizzato in HTML.
Evan Plaice,

2
@EvanPlaice il nome della specifica HTTP PUT come verbo di creazione / aggiornamento (utilizza un modello create + update anziché il più familiare create + recupera + aggiorna) e POST è il verbo "elaborazione dati", nonché il verbo "append" . Roy Fielding nel suo blog ha descritto POST come il verbo da utilizzare quando non si desidera standardizzare l'operazione. Il POST assume la semantica "crea" quando lo si considera aggiungendo un nuovo elemento a una raccolta di elementi. In questo caso, Tragedian ha colpito l'unghia sulla testa usando POST per l'elaborazione o l'aggiunta di un lavoro di stampa.
Rob,

@RobY OK, ha senso. Ad esempio, PUT potrebbe essere utilizzato per rappresentare uno SPROC progettato per immettere dati in un database. Considerando che un POST potrebbe costituire i passaggi intermedi e le mutazioni necessarie per raccogliere / preparare tali dati. Il design dell'operazione POST potrebbe cambiare o essere sostituito man mano che il design si evolve, ma le operazioni PUT rappresentano il modello che (idealmente) non dovrebbe cambiare. Aggiornerei la mia risposta, ma questa fa già un ottimo lavoro nel spiegare la differenza.
Evan Plaice,

4

L'ho già fatto prima. Per stampare un documento restituisco solo una versione pdf di una risorsa. Il client deve solo inviare una richiesta GET per la risorsa con accetta intestazione application / pdf.

Ciò evita anche di creare un nuovo URI per risorse temporanee come il processo di stampa. Anche l'utilizzo dell'intestazione HTTP fa parte di REST e mantiene pulito l'URI.


3

Basta aggiungere un parametro al GET dell'URI corrente

È abbastanza tipico usare un URI per più azioni.

Se stai parlando della stessa risorsa ma di un'azione diversa, la definiresti come parametro.

/ Cliente / {id}? Print = true

Quindi, quando si definisce il metodo GET, si rileva la presenza del parametro di stampa e lo si gestisce in modo diverso.

Il REST è definito nel modo seguente:

  • POST - Crea un record, risorsa o risorsa
  • PUT: aggiornamento, record, risorsa o risorsa
  • ELIMINA: rimuove un, record, risorsa o risorsa

GET, d'altra parte, è pensato per essere utilizzato in diversi modi perché in genere ci sono molte forme diverse che una risorsa può essere recuperata. Questo è anche il motivo per cui le richieste GET sono rappresentate come una stringa di query. Se si stesse lavorando con una risorsa di database, si sarebbe letteralmente recuperato una vista tramite una query, ma REST è intenzionalmente astratto a un livello superiore perché è progettato per gestire molti tipi diversi di risorse.

La specifica REST è piuttosto lungimirante, anche se solo recentemente le API stanno iniziando a usarlo pesantemente.

Se sei interessato a saperne di più sui protocolli REST ti consiglio vivamente di leggere " Haters Gonna Hate HATEOAS ".


Aggiornare:

@Shauna ha sottolineato un buco interessante nel mio ragionamento. Non esiste un vero modo giusto e molte forme sono considerate accettabili. Ci ho pensato un po 'di più e poiché l'uso previsto è quello di trasformare i dati in una rappresentazione diversa, ha senso definire la trasformazione come un nuovo tipo MIME.

Ad esempio, potresti rappresentare l'URI come:

/customer/{id}+print

Dove è possibile impostare la risposta Content-Type su text / html + print. In questo modo avresti anche la possibilità di definire più trasformazioni in futuro.

Per esempio:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

Ad ogni modo, tutte le forme sono accettabili. L'implementazione che decidi dipende più dalle preferenze personali e dalle capacità del tuo server.

A parte: vorrei chiarire dal momento che sembra esserci un po 'di confusione. Il parametro di query "print" e / o il tipo di contenuto vengono utilizzati per specificare la modalità di trasformazione della risorsa. Non come attivare un lavoro di stampa fisico. Per motivi di sicurezza, l'accesso a livello hardware è sempre lasciato all'utente / client / browser.


Per aggiungere - In alternativa all'utilizzo della stringa di query ( ?print=true), è anche possibile utilizzare i parametri URI (cioè - /customer/{id}/printable). Quello che usi dipenderà in gran parte dallo standard che il tuo sistema (CMS, framework, codice in generale) è impostato per gestire. Entrambi sono considerati validi e accettabili .
Shauna

@Shauna Tecnicamente, l'approccio migliore sarebbe quello di utilizzare un tipo MIME specifico per la stampa con l'URI '/ customer / {id} + print' e una risposta MIME-Type di text / html + print. Il vantaggio di tale approccio è che puoi creare trasformazioni per molti tipi MIME (ex text / html, text / x-markdown, application / json, ecc.) Per lo stesso URI. Lo svantaggio della soluzione che presenti è che dovresti creare un URI aggiuntivo (e definire un altro percorso) per ogni tipo MIME diverso. Un po 'sconfigge lo scopo di usare REST.
Evan Plaice,

(cont) Direi che gli hack URI sono un anti-pattern introdotto principalmente dalla comunità ROR ma ciò non significa che non siano utili. Con l'arrivo di migliori server HTTPd di basso livello sta diventando sempre più semplice implementare REST in modo da sfruttare appieno il suo potenziale. Le cose hanno fatto molta strada dai tempi in cui Apache e instradare tutto attraverso index.html era l'unica opzione.
Evan Plaice,

2
GET non dovrebbe fare cambiamenti di stato o avere effetti collaterali. Considera che GET è idempotente, il che significa che il middleware può ritentare la richiesta se non la vede passare. In questo caso, ogni nuovo tentativo comporterebbe una nuova copia del documento appena stampata. ;)
Rob,

@RobY Supponevo che l'azione 'stampa' non avrebbe gestito il processo di stampa fisica del documento in quanto sarebbe stato meglio servito dal browser e dal driver di stampa. Piuttosto, l'output di supporti / stampa restituirebbe una rappresentazione "stampabile" del documento. Pertanto, viene mantenuta l'idempotenza. In ogni caso, mandare lavori di stampa su Internet in modo apolide sarebbe un brutto momento.
Evan Plaice,
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.