API REST: proprietà delle risorse

6

Diciamo che ci sono utenti e animali domestici. Ogni animale domestico ha un singolo utente come proprietario e un unico ID globale. Gli endpoint potrebbero essere

/users/1/pets/2

/pets/2

Mi sembra che la prima opzione non sia intuitiva dato che gli ID non sono coerenti all'interno di un utente. Quale dovrei usare?

    
posta rtainc 26.06.2015 - 11:30
fonte

3 risposte

3

Hai affermato la tua scelta che gli animali domestici hanno un ID unico a livello globale. Ciò significa che un animale domestico può essere trasferito a un altro proprietario senza modificare l'id dell'animale (generalmente una buona cosa per la stabilità sotto refactoring db). Inoltre, significa che, se lo si desidera, è possibile avere due proprietari (ad esempio una coppia o compagni di stanza, ecc.) Per l'animale domestico. (Per non parlare del riferimento diretto a un animale domestico come si nota.)

Pertanto, direi che usa /pets/<id> .

Tuttavia, puoi ancora elencare gli animali domestici per un utente con /users/1/pets e utente per animale domestico con /pets/<id>/user (se limitato a uno o /pets/<id>/users per ulteriori), per uno, perché stiamo parlando dell'API qui non il tuo database normalizzato nascosto dietro di esso. L'uso di semplici numeri interi per ID potrebbe confondere (quindi potresti usare qualcos'altro), ma quando le persone vedono che /pets è un endpoint, penso che lo otterranno.

Dai un'occhiata a un OData, se non l'hai già visto. Un buon modo per sovrapporre il livello REST e fornire filtri, dati annidati e persino join, dal punto di vista dell'API. Ad esempio, il link offre una buona discussione sull'uso delle proprietà di navigazione per specifici join senza dover introdurre chiavi esterne.

Inoltre, penso che alla fine vorrai rimuovere la limitazione di un proprietario per animale domestico, poiché questo non supererà la prova del tempo. Automobili, case, conti bancari, tutti hanno nozioni di più proprietari. I bambini possono avere più guardiani, perché non hanno animali domestici con più proprietari.

    
risposta data 30.06.2015 - 03:13
fonte
3

Se un animale domestico esiste solo nel contesto di un utente, allora ha senso rendere l'animale domestico una risorsa secondaria dell'utente. Ma se puoi immaginare l'animale domestico come una risorsa autonoma, allora sarebbe intuitivo metterlo sulla propria strada. Idealmente, strutturerai le tue risorse nel modo in cui pensi a loro.

    
risposta data 29.06.2015 - 22:31
fonte
0

Attenersi ai fondi; sono fondamentali per una ragione.

<scheme>://<user>:<password>@<server.tld>:<port>/path;parameter?query#fragment

(si noti che l'utilizzo di user:password per identificare userinfo è deprecato ed è una pratica generalmente scorretta. Sono inclusi per completezza, in quanto sono ancora segmenti tecnicamente validi di un URI)

Questi sono i tuoi blocchi fondamentali per la costruzione degli URI. Potresti essere contrario all'estetica del tuo URI perché non stai utilizzando in modo adeguato gli strumenti a tua disposizione. Non c'è niente di particolarmente sbagliato con i frammenti di URI. Ma se i tuoi dati non sono gerarchici - non riesco a pensare a nessuna ragione particolare per cui una persona e un animale domestico dovrebbero essere naturalmente dati gerarchici in un dominio generico - la tua obiezione probabilmente deriva dal fatto che quella è la relazione esatta che hai modellato; uno gerarchico.

Tieni presente che con la giusta comprensione, puoi creare i tuoi URI in modo prosaico come desideri. Quindi, in primo luogo, consentimi di importare alcuni dettagli dalle specifiche URI.

3.3. Path

The path component contains data, usually organized in hierarchical form

...

URI producing applications often use the reserved characters allowed in a segment to delimit scheme-specific or dereference-handler-specific subcomponents. For example, the semicolon (";") and equals ("=") reserved characters are often used to delimit parameters and parameter values applicable to that segment. The comma (",") reserved character is often used for similar purposes.

Questa parte dei parametri del percorso viene solitamente ignorata e sottoutilizzata

3.4. Query

The query component contains non-hierarchical data

La query è molto ben utilizzata (sovrautilizzata secondo me e di solito ignorando quei piccoli dettagli sui dati "non gerarchici")

3.5. Fragment

The fragment identifier component of a URI allows indirect
identification of a secondary resource by reference to a primary
resource and additional identifying information. The identified
secondary resource may be some portion or subset of the primary
resource, some view on representations of the primary resource, or
some other resource defined or described by those representations. A fragment identifier component is indicated by the presence of a
number sign ("#") character and terminated by the end of the URI.

Il frammento è in uso diffuso, ma di solito all'interno di un ambito ristretto di identificazione di rappresentazioni specifiche o di sostituzione di frammenti di vista.

Con queste informazioni messe in discussione, che tipo di relazione tra persone e animali domestici stai provando a modellare con la tua API? Personalmente ritengo che sia molto goffo e innaturale usare l'approccio "tradizionale" di analizzare la gerarchia come si ha con /users/1/pets/2 anche senza considerare gli identificatori. Non c'è nulla di intrinsecamente gerarchico nella relazione tra utenti e animali domestici dalla mia comprensione. Se una relazione gerarchica è ciò che stai per, allora questo è esattamente ciò che hai modellato e la mia opinione non aggiunge valore; in tal caso, hai già quello che vuoi.

Tuttavia, supponiamo di voler modellare una relazione tra users e pets che non è gerarchica. Posso pensare a tre usi di base qui che risulterebbero in due diversi tipi di URI.

Diciamo che non vuoi considerare "animali domestici" e "persone" come entità distinte. Diciamo che stai usando il nome di un animale domestico per trovare una persona. Potresti modellarlo così

/customers?pet=Zeus

Forse dici che stai modellando un negozio di animali e consideri i clienti come un oggetto di dominio principale. Usando questa struttura, non sorprendentemente recupererai i clienti che hanno un animale domestico di nome Zeus.

Diciamo che vuoi usare il nome di una persona per trovare animali domestici

/pets?owner=Alan

Forse stai modellando una clinica veterinaria e gli animali domestici sono l'oggetto principale del tuo sistema di monitoraggio dei farmaci. L'utilizzo di questa struttura non sorprenderà il recupero degli animali domestici di proprietà di Alan.

Per la serie finale di esempi, supponiamo di voler modellare una stretta relazione tra "proprietari" e "animali domestici" senza modellare gerarchicamente la relazione. Si desidera utilizzare un contesto definito nel percorso per recuperare alcuni dati che sono correlati ma non accoppiati semanticamente alla struttura del percorso. Puoi usare il frammento per questo (prima di usarlo cerca una definizione di semantica predefinita per il tipo di media della tua rappresentazione per vedere se questo uso è valido.) In assenza di semantica predefinita, l'utilizzo del frammento non è vincolato e lasciato al design del server In tal caso, ciò sarebbe valido.)

Retrieve the pet named Zeus for user Alan
/users;name=Alan#pet=Zeus

Retrieve the owner of pet named Zeus
/pets/Zeus#owner


/veterinary/patients;owner=Alan#pet=Zeus

Per l'ultimo, stai cercando i record veterinari usando l'entità con name=Alan per recuperare un animale domestico di nome Zeus, o più sinteticamente stai prendendo il cane di Alan.

Ooooohhhhh noooooooeeeee.

    
risposta data 30.06.2015 - 07:05
fonte

Leggi altre domande sui tag