Qual è il miglior metodo di RESTful per restituire il numero totale di elementi in un oggetto?

StackOverflow https://stackoverflow.com/questions/3715981

  •  02-10-2019
  •  | 
  •  

Domanda

sto sviluppando un servizio REST API per un grande sito di social networking in cui sono coinvolto. Finora, sta funzionando grande. Posso emettere GET, POST, PUT e DELETE richieste a URL di oggetti e influenzare i miei dati. Tuttavia, questi dati vengono paging (limitata a 30 risultati alla volta).

Tuttavia, quale sarebbe il modo migliore RESTful per ottenere il numero totale di esempio, i membri, tramite il mio API?

Al momento, ho inviare richieste ad una struttura URL come il seguente:

  • / api / membri I ritorni un elenco dei membri (30 in un momento come detto sopra)
  • / api / membri / 1 -Affects un singolo membro, a seconda del metodo usato richiesta

La mia domanda è: come faccio quindi utilizzare una struttura URL simile a ottenere il numero totale dei membri nella mia applicazione? Ovviamente richiedendo solo il campo id (simile a quella di Facebook Graph API) e il conteggio dei risultati sarebbe inefficace dato solo una fetta di 30 risultati sarebbe tornato solo.

È stato utile?

Soluzione

Mentre la risposta a / API / utenti è paging e restituisce solo il 30, i record, non c'è nulla impedisce di incluso nella risposta anche il numero totale di record, e altre informazioni rilevanti, come le dimensioni della pagina, il numero di pagina / offset, ecc.

Lo StackOverflow API è un buon esempio di quello stesso disegno. Ecco la documentazione per il metodo di utenti - https://api.stackexchange.com/docs/users

Altri suggerimenti

Io preferisco usare intestazioni HTTP per questo tipo di informazioni contestuali.

Per il numero totale di elementi che uso intestazione X-total-count.
Per i collegamenti a successiva, pagina precedente, ecc utilizzare http Link intestazione:
http://www.w3.org/wiki/LinkHeader

Github lo fa allo stesso modo: https://developer.github.com/v3/#pagination

A mio parere è più pulito in quanto può essere utilizzato anche quando si torna a contenuti che non supporta i collegamenti ipertestuali (cioè binari, immagini).

Ho fatto un po 'di ricerche approfondite in questo e ad altre domande relative paging REST ultimamente e ho pensato che costruttivo per aggiungere alcuni dei miei risultati qui. Sto ampliando la domanda un po 'per includere pensieri su paging così come il conteggio in quanto sono legati intimitely.

intestazioni

I metadati di paging è incluso nella risposta sotto forma di intestazioni di risposta. Il grande vantaggio di questo approccio è che il carico utile risposta stessa è solo il richiedente dati effettivi stava chiedendo. Rendere l'elaborazione della risposta facile per i clienti che non sono interessati nelle informazioni di paging.

Ci sono un sacco di intestazioni (standard e personalizzati) utilizzati in natura per restituire paging informazioni correlate, tra cui il conteggio totale.

X-Total-Count

X-Total-Count: 234

Questo è usato in alcuni API ho trovato in natura. Ci sono anche NPM pacchetti per aggiungere il supporto per questa intestazione per esempio Loopback. Alcuni articoli consiglia di impostare questa intestazione pure.

E 'spesso usato in combinazione con l'intestazione Link, che è una soluzione abbastanza buona per il paging, ma manca l'informazione del conteggio totale.

link

Link: </TheBook/chapter2>;
      rel="previous"; title*=UTF-8'de'letztes%20Kapitel,
      </TheBook/chapter4>;
      rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel

mi sento, dalla lettura di un sacco su questo argomento, che il consenso generale è quello di utilizzare la Link intestazione per fornire paging collegamenti ai clienti utilizzando rel=next, rel=previous ecc il problema di questo è che manca l'informazione di quanti record totale ci sono, che è il motivo per cui molte API combinare questo con l'intestazione X-Total-Count.

In alternativa, alcune API e es lo standard JsonApi , utilizzare il formato Link, ma aggiungere l'informazione in una busta risposta anziché un'intestazione. Questo semplifica l'accesso ai metadati (e crea un luogo per aggiungere le informazioni conteggio totale) a scapito della crescente complessità di accedere ai dati effettivi stesso (con l'aggiunta di una busta).

Content-Range

Content-Range: items 0-49/234

Promossa da un articolo del blog chiamato intestazione Gamma , mi si sceglie (per impaginazione)! . L'autore fa un caso forte per utilizzare le intestazioni Range e Content-Range per l'impaginazione. Quando abbiamo letto con attenzione il RFC su queste intestazioni, troviamo che si estende al di là del loro significato gamme di byte era in realtà anticipato dal RFC ed è esplicitamente consentito. Quando viene utilizzato nel contesto della items anziché bytes, l'intestazione Range realtà ci offre un modo sia richiesta una certa gamma di articoli e indica che gamma del risultato totale degli elementi di risposta riguardano. Questa intestazione dà anche un ottimo modo per mostrare il conteggio totale. Ed è un vero e proprio standard che associa per lo più one-to-one per il paging. E 'anche usato in natura .

Busta

Molte API, tra cui l'uno dalla nostra Q & preferita Un sito web utilizzare un busta , un wrapper per i dati che vengono utilizzati per aggiungere meta informazioni sui dati. Inoltre, OData e JsonApi noreferrer entrambi utilizzano una busta di risposta.

Il grande svantaggio di questo (imho) è che l'elaborazione dei dati di risposta diventa più complessa come dati effettivi deve essere trovato da qualche parte nella busta. Inoltre ci sono molti formati differenti per quella busta e si deve utilizzare quella giusta. È significativo che le buste di risposta da OData e JsonApi sono molto diversi, con OData mescolando in metadati in più punti nella risposta.

Separare endpoint

Credo che questo è stato abbastanza coperto in altre risposte. Non ho indagare questo molto perché sono d'accordo con i commenti che questo è fonte di confusione come ora dispone di più tipi di endpoint. Penso che sia più bello se ogni endpoint rappresenta un (insieme di) risorse (s).

Ulteriori pensieri

Noi non solo hanno di comunicare le informazioni di paging meta relative alla risposta, ma permettono anche il client per richiedere specifiche pagine / intervalli. E 'interessante osservare anche questo aspetto per finire con una soluzione coerente. Anche qui possiamo usare intestazioni (header Range sembra molto adatto), o altri meccanismi come parametri di ricerca. Alcuni suggeriscono di trattare pagine dei risultati come risorse separati, che può avere senso in alcuni casi d'uso (ad es /books/231/pages/52. Ho finito per la selezione di una gamma selvaggia di parametri di richiesta frequentemente utilizzati come pagesize, page[size] e limit ecc oltre a supportare l'intestazione Range (e come parametro di richiesta, così).

Si potrebbe restituire il conteggio come un costume header HTTP in risposta ad una richiesta HEAD. In questo modo, se un cliente vuole solo il conteggio, non è necessario per restituire l'elenco effettivo, e non c'è bisogno di un URL aggiuntivo.

(o, se si è in un ambiente controllato da endpoint a endpoint, è possibile utilizzare un personalizzato HTTP verbo come COUNT.)

quando Alternative non hai bisogno di elementi reali

Franci Penov risposta è certamente il modo migliore per andare in modo da tornare sempre articoli insieme a tutti i metadati aggiuntivi sui tuoi entità dalla richiesta. Questo è il modo in cui dovrebbe essere fatto.

, ma a volte il ritorno di tutti i dati non ha senso, perché non si potrebbe essere necessario a tutti. Forse tutto ciò che serve è che i metadati sulla tua risorsa richiesta. Come conteggio totale o il numero di pagine o qualcos'altro. In tal caso si può sempre avere URL Query informi il servizio di non restituire gli articoli, ma piuttosto solo i metadati come:

/api/members?metaonly=true
/api/members?includeitems=0

o qualcosa di simile ...

mi sento di raccomandare l'aggiunta di intestazioni per la stessa, come:

HTTP/1.1 200

Pagination-Count: 100
Pagination-Page: 5
Pagination-Limit: 20
Content-Type: application/json

[
  {
    "id": 10,
    "name": "shirt",
    "color": "red",
    "price": "$23"
  },
  {
    "id": 11,
    "name": "shirt",
    "color": "blue",
    "price": "$25"
  }
]

Per ulteriori dettagli si riferiscono a:

https://github.com/adnan-kamili/rest-api -response formato

Per file di spavalderia:

https://github.com/adnan-kamili/swagger-response-template

Per quanto di "X -" - Prefix è stata sconsigliata. (Vedi: https://tools.ietf.org/html/rfc6648 )

Abbiamo trovato le "Accept-Ranges" come la migliore scommessa per mappare l'impaginazione che vanno: https://tools.ietf.org/html/rfc7233#section-2.3 Come il "Intervallo Unità" può essere sia "byte" o "gettone". Entrambi non rappresentano un tipo di dati personalizzato. (Vedi: https://tools.ietf.org/html/rfc7233#section-4.2 ) Ancora, si afferma che

  

HTTP / 1.1 implementazioni possono ignorare gli intervalli specificati utilizzando altri   unità.

Il che indica:. Usando personalizzato Intervallo Unità non è contro il protocollo, ma può essere ignorato

In questo modo, avremmo dovuto impostare Accept-Ranges a "membri" o qualsiasi altra cosa andavano tipo di unità, ci si aspetterebbe. E in aggiunta, impostare anche il Content-Range per l'attuale gamma. (Vedi: https://www.w3.org/Protocols/ RFC2616 / RFC2616-sec3.html # sec3.12 )

In ogni caso, vorrei aderire alla raccomandazione del RFC7233 ( https: // strumenti. ietf.org/html/rfc7233#page-8 ) per inviare un 206 invece di 200:

  

Se tutte le premesse sono vere, il server supporta il
Gamma   campo di intestazione per la risorsa di destinazione, e il campo specificato (s) sono
  valido e soddisfacibile (come definito nella Sezione 2.1), il server dovrebbe
  inviare un (Contenuto parziale) risposta 206 con un carico utile che contiene una
  o rappresentazioni più parziali che corrispondono alla
soddisfacibile   gamme richieste, come definito nella sezione 4.

Quindi, di conseguenza, ci avrebbe le seguenti HTTP intestazione campi:

Per Partial Content:

206 Partial Content
Accept-Ranges: members
Content-Range: members 0-20/100

per il contenuto completo:

200 OK
Accept-Ranges: members
Content-Range: members 0-20/20

Che dire di un nuovo punto finale> / api / soci / conteggio che ha appena chiama Members.Count () e restituisce il risultato

Sembra più semplice per aggiungere solo un

GET
/api/members/count

e restituire il conteggio totale dei membri

A volte framework (come $ risorse / AngularJS) richiedono un array come risultato della query, e non si può davvero avere una risposta come {count:10,items:[...]} in questo ho negozio caso "contare" in responseHeaders.

P. S. In realtà si può fare con $ risorse / AngularJS, ma ha bisogno di alcuni ritocchi.

Quando si richiede i dati impaginato, si sa (dal valore esplicito dimensioni della pagina parametro o valore di default dimensioni della pagina) la dimensione della pagina, in modo da sapere se hai tutti i dati in risposta o meno. Quando c'è meno dati in risposta che è una dimensione di pagina, allora hai i dati interi. Quando una pagina intera viene restituito, si deve chiedere di nuovo per un'altra pagina.

Io preferisco avere endpoint separato per count (o stesso endpoint con il parametro countOnly). Perché si potrebbe preparare l'utente finale per lungo / processo che richiede tempo, mostrando progressbar correttamente iniziati.

Se si desidera tornare datasize a ogni risposta, ci dovrebbe essere pageSize, offset mentionded pure. Ad essere onesti il ??modo migliore è quello di ripetere un filtro richiesta è troppo. Ma la risposta è diventata molto complessa. Quindi, preferisco endpoint dedicato al conteggio di ritorno.

<data>
  <originalRequest>
    <filter/>
    <filter/>
  </originalReqeust>
  <totalRecordCount/>
  <pageSize/>
  <offset/>
  <list>
     <item/>
     <item/>
  </list>
</data>

Couleage mio, preferisce un parametro countOnly per endpoint esistente. Così, quando specificato la risposta contiene metadati solo.

endpoint? Filter = valore

<data>
  <count/>
  <list>
    <item/>
    ...
  </list>
</data>

endpoint? Filter = valore & countOnly = true

<data>
  <count/>
  <!-- empty list -->
  <list/>
</data>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top