Ci sono problemi con l'implementazione di metodi HTTP personalizzati?

27

Abbiamo un URL nel seguente formato

/instance/{instanceType}/{instanceId}

Puoi chiamarlo con i metodi HTTP standard: POST, GET, DELETE, PUT. Tuttavia, ci sono alcune altre azioni che intraprendiamo come "Salva come bozza" o "Curato"

Pensavamo di poter utilizzare solo metodi HTTP personalizzati come: DRAFT, VALIDATE, CURATE

Penso che sia accettabile dal momento che gli standard dicono

"The set of common methods for HTTP/1.1 is defined below. Although this set can be expanded, additional methods cannot be assumed to share the same semantics for separately extended clients and servers."

E strumenti come WebDav creano alcune delle loro estensioni.

Ci sono problemi con cui qualcuno si è imbattuto con metodi personalizzati? Sto pensando a server proxy e firewall, ma qualsiasi altra area di interesse è ben accetta. Dovrei rimanere al sicuro e avere solo un parametro URL come action = validate | curate | draft?

    
posta Juan Mendes 04.04.2013 - 02:10
fonte

3 risposte

36

Uno dei limiti fondamentali di HTTP e la caratteristica di progettazione centrale di REST è una interfaccia uniforme fornita da (tra le altre cose) un piccolo insieme di metodi fissi che applicare universalmente a tutte le risorse. Il vincolo di interfaccia uniforme ha un numero di svantaggi e svantaggi. Cito da Fielding liberamente qui.

Un'interfaccia uniforme:

  • è più semplice.
  • disaccoppia le implementazioni dai servizi che forniscono.
  • consente un'architettura a livelli, inclusi elementi come load balancer (nginx) HTTP e cache (vernice).

D'altra parte, un'interfaccia uniforme:

  • degrada l'efficienza, perché le informazioni vengono trasferite in un modulo standard piuttosto che in uno specifico per le esigenze di un'applicazione.

I compromessi sono "progettati per il caso comune del Web" e hanno permesso la costruzione di un grande ecosistema che fornisce soluzioni a molti dei problemi comuni nelle architetture web. Aderire a un'interfaccia uniforme consentirà al tuo sistema di beneficiare di questo ecosistema, mentre rompendolo lo renderà così difficile. Potresti voler utilizzare un servizio di bilanciamento del carico come nginx, ma ora puoi utilizzare solo un servizio di bilanciamento del carico che comprende DRAFT e CURATE. Potresti voler utilizzare un livello di cache HTTP come Varnish, ma ora puoi utilizzare solo un livello di cache HTTP che comprenda DRAFT e CURATE. Potresti voler chiedere aiuto a qualcuno per risolvere un errore del server, ma nessun altro conosce la semantica per una richiesta di CURATE. Potrebbe essere difficile cambiare le tue librerie client o server preferite per capire e implementare correttamente i nuovi metodi. E così via.

Il modo corretto di * per rappresentarlo è una trasformazione dello stato sulla risorsa (o risorse correlate). Non fai DRAFT di un post, ne trasformi lo stato draft in true oppure crei una risorsa draft che contiene le modifiche e i link alle versioni precedenti della bozza. Non si CORRE un post, si trasforma il suo stato curated in true o si crea una risorsa curation che collega il post con l'utente che lo ha curato.

* Corretto dal fatto che segue da vicino i principi architettonici di REST.

    
risposta data 04.04.2013 - 03:14
fonte
7

Preferirei progettarli come sottorisorse, su cui esegui una richiesta POST.

Considera di avere una risorsa in /instance/type/1 , vorrei che la rappresentazione di quella risorsa trasmettesse un paio di link a "azioni" che possono essere eseguite sulla risorsa, come /instance/type/1/draft e /instance/type/1/curate . In JSON, questo potrebbe essere semplice come:

{
    "some property":"the usual value",
    "state": "we can still inform the client about the current state",
    "draft": "http://server/instance/type/1/draft",
    "curate": "http://server/instance/type/1/curate"
}

Ciò consente al client di essere molto esplicito su cosa deve accadere, durante la richiesta POST al link fornito dal membro curate . La risorsa pubblicata potrebbe includere argomenti che descrivono l'evento che potrebbe, forse, infliggere una transizione di stato.

L'approccio "ingenuo" di muoversi tra i possibili stati di una risorsa ha lo svantaggio di non catturare gli eventi che hanno portato a queste transizioni.

Le transizioni di stato di solito si verificano in risposta a eventi specifici, e preferisco catturare quegli eventi piuttosto che lasciare che il cliente decida che qualcosa è ora in uno "stato" specifico. Inoltre rende la convalida molto più difficile. Inoltre, non saresti in grado di acquisire alcun 'argomento' a meno che tu non descriva anche quelli nello stato stesso. E poi diventa tutto icky quando un codice cambia quelli senza transizione di stato reale, e la convalida è richiesta, e l'intera faccenda diventa rapidamente un disastro.

    
risposta data 11.07.2014 - 11:59
fonte
5

Penso che il metodo HTTP personalizzato sia il modo migliore per implementare le azioni dell'entità. Aggiungere l'azione al corpo dell'entità (POST) non sembra giusto, non fa parte della tua entità (anche se il risultato potrebbe essere salvato in esso). Inoltre, l'utilizzo dei proxy dei metodi HTTP personalizzati potrebbe determinare le loro azioni senza la necessità di analizzare il corpo dell'entità.

È come CRUD, vorresti sempre implementarli, ma hai anche il tuo specifico insieme di azioni (per enitity). Io davvero non vedo quale sarebbe il problema estendendoli.

Anche @Rein Henrichs "Non disegni un post, trasformi il suo stato bozza in vero o crei una bozza di risorsa" mi sembra falso. Una proprietà drafts verrebbe utilizzata per il salvataggio permanente dello stato, non per effettuare la trasformazione. Le azioni non portano necessariamente a uno "stato", o vengono salvate in una proprietà. Creare un'entità separata per ogni stato / trasformazione sembra ancora più sfocata .. prova a mantenere lo stesso riferimento (URI) all'entità.

    
risposta data 08.03.2014 - 12:26
fonte

Leggi altre domande sui tag