Indica se incorporare risorse collegate nell'API REST

5

Sto costruendo un'API REST in cui i client possono interrogare i messaggi inviati dall'utente, in questo modo:

GET http://example.com/api/v1/messages?from=0&to=100

Risposta:

[
    {
        "id": 12345,
        "text": "Hello, world!"
    },
    {
        "id": 12346,
        "text": "Testing, testing"
    },
    ...
]

Ora, ho bisogno di includere il nome dell'utente che ha inviato il messaggio. Posso pensare a 4 modi per memorizzare queste informazioni, ma non riesco a decidere quale sia il migliore:

Opzione 1:

[
    {
        "id": 12345,
        "sender_id": 16,
        "text": "Hello, world!"
    }
]

Questo metodo è il più efficiente su larga scala - se il client esegue una query sull'API molte volte, può memorizzare nella cache una mappa dell'ID utente per denominarla e riutilizzarla. Tuttavia, per le query una tantum, raddoppia la quantità di chiamate API che il client deve eseguire (una volta per l'elenco dei messaggi e un'altra per trovare il nome per un determinato ID utente).

Opzione 2:

[
    {
        "id": 12345,
        "sender_name": "John Smith",
        "text": "Hello, world!"
    }
]

Questo metodo è il più semplice per il consumo del client, ma se l'API deve essere sempre modificata per includere l'ID del mittente (ad esempio per il collegamento da un messaggio all'altro), avrei bisogno di avere due campi "mittente" nell'oggetto messaggio, sender_id e sender_name , che è essenzialmente una versione peggiore dell'opzione 3.

Opzione 3:

[
    {
        "id": 12345,
        "sender": {
            "id": 16,
            "name": "John Smith"
        },
        "text": "Hello, world!"
    }
]

Questo approccio incorpora l'oggetto mittente in ciascun messaggio, che lo rende a prova di futuro e richiede solo una singola chiamata API per query. Tuttavia, aggiunge molte informazioni ridondanti se ci sono molti messaggi e pochi utenti (ad esempio, interrogando tutti i messaggi inviati da un singolo utente).

Opzione 4:

{
    "users": [
        {
            "id": 16,
            "name": "John Smith"
        },
        ...
    ],
    "messages": [
        {
            "id": 12345,
            "sender_id": 16,
            "text": "Hello, world!"
        }
    ]
}

Questo risolve il problema della ridondanza con # 3, ma aggiunge molta complessità alla struttura dell'oggetto risposta.

    
posta Andrew Sun 17.03.2016 - 21:23
fonte

2 risposte

3

Probabilmente dovresti optare per l'opzione 1, ma reso più RESTful. Potrebbe anche aver senso fornire qualcosa come l'opzione 3/4. Non c'è nulla che ti costringa a sceglierne solo uno.

Tuttavia, ciò che dovresti fare è sostituire gli id con link . Invece di avere un "sender_id", dovresti avere un puntamento URI a quella risorsa utente. Nota come questo significa che non ho bisogno di sapere quale URI aggiungere "sender_id" o come formattare. Sfortunatamente, JSON non ha un tipo per i collegamenti. Dovrai esaminare i formati hypermedia incorporati in JSON , ad es. HAL o JSON-LD.

Ora hai ragione che se voglio recuperare il record, ho bisogno di fare due richieste. La buona notizia, tuttavia, è che quelle richieste saranno memorizzate nella cache dal meccanismo normale di HTTP. Una rete di distribuzione dei contenuti può persino memorizzare nella cache le risorse tra gli utenti riducendo il carico sui server e la latenza per gli utenti. Naturalmente, non mi è precluso avere una risorsa che restituisce tutti gli utenti oi dati per tutti gli utenti che hanno fornito un elenco di URI utente in modo da poter effettuare richieste batch. Potresti considerare OData come un mezzo organizzato per fornire tali funzionalità di query, ma puoi certamente fare qualcosa di più semplice. Ad esempio, quando si restituiscono i messaggi, è anche possibile aggiungere un collegamento a, ad esempio, "contatti recenti" con i dati espansi per tutti gli utenti nell'elenco corrente di messaggi. Nota come dico di fornire un link e non aggiungere una risorsa messages/users/ . Potresti aggiungere una tale risorsa, ma non avrei bisogno di conoscere la tua struttura URI per trovarla. Questo mi rende più facile e ti consente di cambiare i tuoi URI in futuro senza rompere i consumatori.

A volte ci saranno garanzie transazionali che vorrete imporre. Ad esempio, in quanto sopra, è possibile ottenere i messaggi, quindi richiedere i contatti recenti e tale elenco potrebbe differire dall'elenco degli URI del mittente presenti nei messaggi a causa di una condizione di competizione. Nei casi in cui è importante garantire quel tipo di atomicità, è necessario incorporare le risorse. Alcuni dei formati hypermedia cui ho fatto riferimento sopra forniscono un meccanismo per questo. Di solito, queste situazioni corrisponderanno naturalmente a una nuova risorsa. Ricorda, tu non hai bisogno di una corrispondenza di 1-1 tra risorse e "entità" o qualsiasi altra cosa. In effetti, una corrispondenza di tipo 1-1 probabilmente significa che stai facendo qualcosa di sbagliato. Nel complesso, tuttavia, dovresti cercare di minimizzare i punti che richiedono tali garanzie transazionali. Nell'esempio sopra, non sarebbe necessario, poiché anche se mancasse un mittente dall'elenco di "contatti recenti", potrei semplicemente richiedere le loro informazioni individualmente.

    
risposta data 18.03.2016 - 00:09
fonte
1

Penso che dipenda anche dai bisogni. Supponiamo che l'app client mostri un elenco di 100 elementi e che ogni messaggio debba visualizzare il mittente. Se inseriamo tutti i dati richiesti nel JSON (cioè l'ID del mittente e il nome del mittente), facciamo una sola richiesta. Se invece ci sono collegamenti ai mittenti, abbiamo 101 richieste. Non dirmi che questo è efficiente:)

Ma sono d'accordo sul fatto che gli URI siano una buona pratica, ad esempio quando si implementa una funzionalità quando l'utente può fare clic sul nome del mittente e vedere maggiori informazioni su di lui. Quindi la mia opinione su questa struttura sarebbe la seguente:

[
    {
        "id": 12345,
        "sender": {
            "link": "www.api.example.com/users/16",
            "name": "John Smith"
        },
        "text": "Hello, world!"
    }
]
    
risposta data 21.10.2016 - 09:38
fonte

Leggi altre domande sui tag