Un'API REST può restituire più risorse come un'unica risorsa composta?

9

Sono in procinto di creare un'API REST e al momento sto riscontrando il seguente problema:

  • Foo è la prima risorsa. Le operazioni CRUD possono essere applicate tramite l'URI /foo/ .
  • Bar è la seconda risorsa. Le operazioni CRUD possono essere applicate tramite l'URI /bar/ .
  • Ogni Foo è associato a zero o a Bar . Il motivo per cui non considero Bar come una subresource di Foo è perché la stessa% di istanza diBar può essere condivisa tra il mutiple Foo s. Quindi ho capito che è meglio accedervi tramite un URI indipendente anziché /foo/[id]/bar .

Il mio problema è che in una quantità significativa di casi, i clienti che richiedono un'istanza Foo sono interessati anche all'istanza Bar associata. Attualmente, ciò significa che devono eseguire due query invece di una. Voglio introdurre un modo che consenta di ottenere entrambi gli oggetti con una singola query, ma non so come modellare l'API per farlo. Quello che ho inventato finora:

  • Potrei introdurre un parametro di query simile a questo: /foo/[id]?include_bar=true . Il problema con questo approccio è che la rappresentazione della risorsa (ad esempio la struttura JSON) della risposta dovrebbe apparire diversa (ad esempio un contenitore come { foo: ..., bar: ... } invece di un solo Foo serializzato), che rende la risorsa Foo endpoint "eterogeneo". Non penso sia una buona cosa. Quando si esegue una query su /foo , i client devono sempre ottenere la stessa rappresentazione di risorse (struttura), indipendentemente dai parametri di query.
  • Un'altra idea è di introdurre un nuovo endpoint di sola lettura, ad es. %codice%. In questo caso, non è un problema restituire una rappresentazione come /fooandbar/[foo-id] , perché allora è solo la rappresentazione "ufficiale" della risorsa { foo: ..., bar: ... } . Tuttavia, non so se un tale endpoint helper sia realmente RESTful (questo è il motivo per cui ho scritto "can" nel titolo della domanda. Naturalmente è tecnicamente possibile, ma non so se sia una buona idea).

Che ne pensi? Ci sono altre possibilità?

    
posta ceran 10.11.2016 - 13:50
fonte

2 risposte

4

Un'API REST livello 3 ti restituirebbe un Foo e anche un link che indica il Bar correlato.

GET /foo/123
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456"/>
</foo>

Potresti quindi aggiungere una funzionalità "drill-down" alla tua API che consente la navigazione dei link;

GET /foo/123?drilldown=bar
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456">
    <bar id="456">
      ..bar stuff...
    </bar>
  </link>
</foo>

La funzionalità di drill down si posiziona di fronte alle API e intercetta le risposte. Effettuerebbe le chiamate di drill down e compilerà i dettagli prima di restituire la risposta al chiamante.

Questa è una cosa abbastanza comune in REST di livello 3 in quanto riduce notevolmente la chattiness client / server su HTTP lento. La società per cui lavoro produce un'API REST di livello 3 con esattamente questa funzione.

Aggiornamento: Per quello che vale, ecco come potrebbe apparire in JSON. Questo è il modo in cui la nostra API lo strutturerebbe. Nota che puoi annidare i tuoi drill down per tirare link di link ecc.

GET /foo/123?drilldown=bar

{
  "self": {
    "type": "thing.foo",
    "uri": "/foo/123=?drilldown=bar",
    "href": "http://localhost/api/foo/123?drilldown=bar"
  },
  "links": [
    {
      "rel": "bar",
      "rev": "foo",
      "type": "thing.bar",
      "uri": "/bar/456",
      "href": "http://localhost/api/bar/456"
    }
  ],
  "_bar": [
    {
      "self": {
        "type": "thing.bar",
        "uri": "/bar/456",
        "href": "http://localhost/api/bar/456"
      },
      "links": [
        {
          ..other link..
        },
        {
          ..other link..
        }
      ]
    }
  ]
}
    
risposta data 10.11.2016 - 14:25
fonte
4

Se il 95% di tutte le query desidera Foo e Bar , quindi semplicemente restituiscilo all'interno dell'oggetto Foo quando richiedi una% codice%. Basta aggiungere una proprietà Foo (o qualche altro termine per la relazione) e inserire l'oggetto bar lì. Se la relazione non esiste, quindi usa null.

Penso che stai pensando troppo a questo:)

    
risposta data 10.11.2016 - 14:06
fonte

Leggi altre domande sui tag