URL di REST annidati e ID padre, che è una progettazione migliore?

14

Ok, abbiamo due risorse: Album e Song . Ecco l'API:

GET,POST /albums
GET,POST /albums/:albumId
GET,POST /albums/:albumId/songs
GET,POST /albums/:albumId/songs/:songId

Sappiamo che odiamo qualche canzone, per esempio è chiamata Susy . Dove dovremmo inserire search azione?

Un'altra domanda. Ok, ora è più reale. Apriamo l'album 1 e cariciamo tutte le canzoni. Creiamo oggetti JS, ognuno contiene i dati dei brani e ha pochi metodi come: remove , update .

L'oggetto Song ha ID, nome e materiale, ma non ha idea di quale sia il genitore a cui appartiene, perché recuperiamo l'elenco dei brani per query e non sarà così bello restituire gli ID genitori con ciascuno di essi. Mi sbaglio?

Quindi, vedo poche soluzioni, ma non ne sono sicuro.

  1. Rendi l'ID genitore facoltativo - come parametro get. Questo approccio uso al momento, ma credo che sia brutto.

    List,Create /songs?album=albumId
    Update,Delete /songs/:songId
    Get /songs/?name=susy # also, solution for first question
    
  2. ibrida. È ora utile perché abbiamo bisogno dell'ID album per eseguire la query OPTIONS per ottenere i meta-dati.

    List,Create /album/:albumId/songs
    Update,Delete /songs/:songId
    POST /songs/search # also, solution for first question
    
  3. Restituisci URL completo con ogni istanza di risorsa. L'API è la stessa, ma otterremo brani come questo:

    id: 5
    name: 'Elegy'
    url: /albums/2/songs/5
    

    Ho sentito che questo approccio si chiama HATEOAS.

  4. Quindi ... Per fornire l'ID genitore

    id: 5
    name: 'Elegy'
    albumId: 2
    

Quale è meglio? O forse sono stupido? Dai qualche consiglio, ragazzi!

    
posta dt0xff 02.03.2015 - 20:29
fonte

1 risposta

25

Where we should put search action?

In GET /search/:text . Ciò restituirà un array JSON contenente le corrispondenze, ogni corrispondenza contenente l'album a cui appartiene. Questo ha senso, perché il cliente potrebbe essere interessato non alla traccia in sé, ma all'intero album (immagina di cercare una canzone che, tu credi, fosse nello stesso album di quello che ricordi il nome).

it will be not that good to return parent ids with each so. Am I wrong?

Le singole tracce possono contenere l'album. Questo assicurerà che la rappresentazione della traccia sia uniforme se puoi ottenere una traccia tramite un album o tramite la ricerca (nessun album qui).

Which is better?

Come affermato in precedenza, anche l'album ha senso. Mentre il terzo punto (con l'URI relativo) può essere interessante in alcuni casi (non devi pensare al modo in cui l'URI dovrebbe essere formato), ha l'inconveniente di non fornire esplicitamente l'album. Il quarto punto corregge questo. Se vedi il vantaggio di avere l'URI relativo nella risposta, puoi combinare i punti 3 e 4.

Or maybe I'm dumb?

Scegliere un buon URI non è un compito facile, soprattutto perché non esiste una risposta giusta. Se sviluppi il client contemporaneamente all'API, può aiutarti a visualizzare meglio come l'API potrebbe essere utilizzata. Detto questo, altre persone potrebbero quindi preferire altri usi a cui non stavi pensando durante lo sviluppo dell'API.

Un aspetto che può essere problematico è il modo in cui organizzi i dati internamente, cioè l'uso di una gerarchia. Dal tuo commento, ti stai chiedendo cosa dovrebbe contenere una risposta a GET /artist/1/album/10/song/3/comment/23 , che mostra una visione molto orientata agli alberi. Ciò può causare alcuni problemi durante l'estensione del sistema in un secondo momento. Ad esempio:

  • Che cosa succede se un brano non ha un album?
  • Che cosa succede se un album ha più artisti?
  • Che cosa succede se si desidera aggiungere una funzione che consenta di commentare gli album?
  • Che cosa succede se devono essere presenti commenti dei commenti?
  • ecc.

Questo è essenzialmente il problema che ho spiegato nel mio blog : una rappresentazione ad albero ha troppe limitazioni per essere efficacemente utilizzata in molti casi.

Cosa succede se distruggi la gerarchia? Vediamo.

  1. GET /albums/:albumId restituisce un JSON contenente le meta informazioni sull'album (come l'anno in cui è stato pubblicato o l'URI del JPEG che mostra la copertina dell'album) e una serie di tracce. Ad esempio:

    GET /albums/151
    
    {
        "id": 151,
        "gid": "dbd3cec7-b927-423f-894b-742c4c7b54ce",
        "name": "Yellow Submarine",
        "year": 1969,
        "genre": "Psychedelic rock",
        "artists": ["John Lennon", "Paul McCartney", ...],
        "tracks": [
            {
                "id": 90224,
                "title": "Yellow Submarine",
                "length": "2:40"
            },
            {
                "id": 83192,
                "title": "Only a Northern Song",
                "length": "3:24"
            }
            ...
        ]
    }
    

    Perché includo, ad esempio, la lunghezza di ogni traccia? Perché immagino che il cliente che mostra un album possa essere interessato elencando le tracce per titolo, ma mostra anche la lunghezza di ogni traccia, come la maggior parte dei clienti. D'altra parte, non posso mostrare il compositore (s) o l'artista (s) per ogni traccia, perché decido che questa informazione non è necessaria a questo livello. Ovviamente, le tue scelte potrebbero essere diverse.

  2. GET /tracks/:trackId restituisce le informazioni su una traccia specifica. Poiché non esiste più alcuna gerarchia, non è necessario indovinare l'album o l'artista: l'unica cosa che devi sapere è l'identificativo della traccia stessa.

    O forse anche no? Cosa succede se puoi specificarlo per nome con GET /tracks/:trackName ?

    GET /tracks/Only%20a%20Northern%20Song
    
    {
        "id": 83192,
        "gid": "8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b",
        "title": "Only a Northern Song",
        "writers": ["George Harrison"],
        "artists": ["John Lennon", "Paul McCartney", "Ringo Starr"],
        "length": "3:24",
        "record-date": 1967,
        "albums": [151, 164],
        "soundtrack": {
            "uri": "http://audio.example.com/tracks/static/83192.mp3",
            "alias": "Beatles - Only a Northern Song.mp3",
            "length-bytes": 3524667,
            "allow-streaming": true,
            "allow-download": false
        }
    }
    

    Ora guarda più vicino a albums ; cosa vedi? Giusto, non uno, ma due album. Se hai una gerarchia, non puoi farlo (a meno che non duplichi il record).

  3. GET /comments/:objectGid . Potresti aver individuato i brutti GUID nelle risposte. Questi GUID consentono di identificare l'entità attraverso il database al fine di eseguire attività che possono essere applicate ad album, artisti o tracce. Ad esempio commentare.

    GET /comments/8d9c4311-9d7b-40a4-8aeb-4fe96247fe2b
    
    [
        {
            "author": {
                "id": 509931,
                "display-name": "Arseni Mourzenko"
            },
            "text": "What a great song! (And I'm proud of the usefulness of my comment)",
            "concerned-object": "/tracks/83192"
        }
    ]
    

    Il commento fa riferimento all'oggetto interessato, rendendo possibile l'accesso ad esso quando accede al commento al di fuori del suo contesto (ad esempio quando si moderano gli ultimi commenti attraverso GET /comments/latest ).

Nota che questo non significa che devi evitare qualsiasi forma di gerarchia nella tua API. Ci sono casi in cui ha senso. Come regola generale:

  • Se la risorsa non ha senso al di fuori del contesto della sua risorsa genitore, usa la gerarchia.

  • Se la risorsa può vivere (1) da solo o (2) in un contesto di risorse parent di diversi tipi o (3) avere più genitori, la gerarchia non dovrebbe essere utilizzata.

Per esempio, le linee di un file non hanno senso al di fuori del contesto di un file, quindi:

GET /file/:fileId

e

GET /file/:fileId/line/:lineIndex

stanno bene.

    
risposta data 02.03.2015 - 21:20
fonte

Leggi altre domande sui tag