Suggerimenti sulle prestazioni

Questo documento illustra alcune tecniche che puoi utilizzare per migliorare le prestazioni dell'applicazione. In alcuni casi, vengono utilizzati esempi di altre API o di API generiche per illustrare le idee presentate. Tuttavia, gli stessi concetti sono applicabili all'API Fitness.

Compressione utilizzando gzip

Un modo semplice e comodo per ridurre la larghezza di banda necessaria per ogni richiesta è attivare la compressione gzip. Sebbene questo richieda più tempo di CPU per decomprimere i risultati, in genere è vantaggioso ottenere un compromesso con i costi di rete.

Per ricevere una risposta con codifica gzip devi svolgere due operazioni: impostare un'intestazione Accept-Encoding e modificare lo user agent in modo che contenga la stringa gzip. Ecco un esempio di intestazioni HTTP formattate correttamente per attivare la compressione gzip:

Accept-Encoding: gzip
User-Agent: my program (gzip)

Utilizzo delle risorse parziali

Un altro modo per migliorare le prestazioni delle chiamate API consiste nell'inviare e ricevere solo la parte dei dati che ti interessa. Ciò consente alla tua applicazione di evitare di trasferire, analizzare e archiviare i campi non necessari, in modo da poter utilizzare le risorse come rete, CPU e memoria in modo più efficiente.

Esistono due tipi di richieste parziali:

  • Risposta parziale: una richiesta in cui si specificano quali campi includere nella risposta (utilizza il parametro di richiesta fields).
  • Patch: una richiesta di aggiornamento a cui vengono inviati solo i campi che vuoi modificare (utilizza il verbo HTTP PATCH).

Per ulteriori informazioni sull'invio di richieste parziali, consulta le sezioni seguenti.

Risposta parziale

Per impostazione predefinita, il server restituisce la rappresentazione completa di una risorsa dopo l'elaborazione delle richieste. Per ottenere prestazioni migliori, puoi chiedere al server di inviare solo i campi di cui hai davvero bisogno e ottenere invece una risposta parziale.

Per richiedere una risposta parziale, utilizza il parametro di richiesta fields per specificare i campi da restituire. Puoi utilizzarlo per qualsiasi richiesta che restituisca dati di risposta.

Tieni presente che il parametro fields influisce solo sui dati di risposta, non sui dati che devi inviare. Per ridurre la quantità di dati che invii quando modifichi le risorse, utilizza una richiesta patch.

Esempio

L'esempio seguente mostra l'utilizzo del parametro fields con un'API "Demo" generica (di fantasia).

Richiesta semplice: questa richiesta HTTP GET omette il parametro fields e restituisce la risorsa completa.

https://www.googleapis.com/demo/v1

Risposta completa alla risorsa: i dati completi sulla risorsa includono i seguenti campi, insieme a molti altri che sono stati omessi per brevità.

{
  "kind": "demo",
  ...
  "items": [
  {
    "title": "First title",
    "comment": "First comment.",
    "characteristics": {
      "length": "short",
      "accuracy": "high",
      "followers": ["Jo", "Will"],
    },
    "status": "active",
    ...
  },
  {
    "title": "Second title",
    "comment": "Second comment.",
    "characteristics": {
      "length": "long",
      "accuracy": "medium"
      "followers": [ ],
    },
    "status": "pending",
    ...
  },
  ...
  ]
}

Richiesta di risposta parziale: la seguente richiesta per la stessa risorsa utilizza il parametro fields per ridurre in modo significativo la quantità di dati restituiti.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

Risposta parziale: in risposta alla richiesta riportata sopra, il server restituisce una risposta contenente solo le informazioni del tipo insieme a un array di elementi essenziali che include solo il titolo HTML e le informazioni sulla lunghezza di ogni elemento.

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

Tieni presente che la risposta è un oggetto JSON che include solo i campi selezionati e i relativi oggetti padre.

Più avanti troverai informazioni dettagliate su come formattare il parametro fields, seguito da maggiori dettagli sul contenuto esatto della risposta.

Riepilogo della sintassi del parametro dei campi

Il formato del valore del parametro di richiesta fields è liberamente basato sulla sintassi XPath. La sintassi supportata è riepilogativa di seguito e ulteriori esempi sono forniti nella sezione seguente.

  • Utilizza un elenco separato da virgole per selezionare più campi.
  • Utilizza a/b per selezionare un campo b nidificato all'interno del campo a; utilizza a/b/c per selezionare un campo c nidificato all'interno di b.

    Eccezione: per le risposte API che utilizzano "wrapper" dei dati, in cui la risposta è nidificata all'interno di un oggetto data simile a data: { ... }, non includere "data" nella specifica fields. L'inclusione dell'oggetto dati con una specifica dei campi come data/a/b causa un errore. Devi solo utilizzare una specifica fields come a/b.

  • Utilizza un selettore secondario per richiedere un insieme di sottocampi specifici di array o oggetti inserendo le espressioni tra parentesi "( )".

    Ad esempio: fields=items(id,author/email) restituisce solo l'ID articolo e l'indirizzo email dell'autore per ogni elemento nell'array di articoli. Puoi anche specificare un singolo sottocampo, dove fields=items(id) equivale a fields=items/id.

  • Se necessario, utilizza i caratteri jolly nelle selezioni di campi.

    Ad esempio: fields=items/pagemap/* seleziona tutti gli oggetti in una mappa pagine.

Altri esempi di utilizzo del parametro campi

Gli esempi di seguito includono descrizioni di come il valore del parametro fields influisce sulla risposta.

Nota: come per tutti i valori dei parametri di ricerca, il valore del parametro fields deve essere codificato nell'URL. Per una migliore leggibilità, gli esempi in questo documento omettono la codifica.

Identifica i campi da restituire o seleziona campi selezionati.
Il valore del parametro di richiesta fields è un elenco di campi separato da virgole e ogni campo è specificato in relazione alla radice della risposta. Pertanto, se stai eseguendo un'operazione list, la risposta è una raccolta e generalmente include un array di risorse. Se stai eseguendo un'operazione che restituisce una singola risorsa, i campi vengono specificati per quella risorsa. Se il campo selezionato è (o fa parte) di un array, il server restituisce la parte selezionata di tutti gli elementi nell'array.

Ecco alcuni esempi a livello di raccolta:
Esempi Effetto
items Restituisce tutti gli elementi nell'array di elementi, inclusi tutti i campi in ogni elemento, ma nessun altro campo.
etag,items Restituisce sia il campo etag che tutti gli elementi nell'array di elementi.
items/title Restituisce solo il campo title per tutti gli elementi nell'array di articoli.

Quando viene restituito un campo nidificato, la risposta include gli oggetti principali che le contengono. I campi principali non includono altri campi secondari, a meno che non siano selezionati esplicitamente.
context/facets/label Restituisce solo il campo label per tutti i membri dell'array facets, che è a sua volta nidificato sotto l'oggetto context.
items/pagemap/*/title Per ogni elemento nell'array di articoli, restituisce solo il campo title (se presente) di tutti gli oggetti secondari di pagemap.

Ecco alcuni esempi a livello di risorsa:
Esempi Effetto
title Restituisce il campo title della risorsa richiesta.
author/uri Restituisce il sottocampo uri dell'oggetto author nella risorsa richiesta.
links/*/href
Restituisce il campo href di tutti gli oggetti secondari di links.
Richiedi solo parti di campi specifici utilizzando le selezioni secondarie.
Per impostazione predefinita, se la richiesta specifica campi specifici, il server restituisce gli oggetti o gli elementi dell'array nella loro interezza. Puoi specificare una risposta che includa solo alcuni sottocampi. A tale scopo, utilizza la sintassi di sottoselezione "( )", come nell'esempio riportato di seguito.
Esempio Effetto
items(title,author/uri) Restituisce solo i valori di title e uri di autore per ogni elemento nell'array di elementi.

Gestione delle risposte parziali

Dopo che un server elabora una richiesta valida che include il parametro di ricerca fields, restituisce un codice di stato HTTP 200 OK, insieme ai dati richiesti. Se il parametro di ricerca fields contiene un errore o non è altrimenti valido, il server restituisce un codice di stato HTTP 400 Bad Request e un messaggio di errore che indica all'utente che cosa era sbagliato nella selezione dei campi (ad es. "Invalid field selection a/b").

Ecco un esempio di risposta parziale mostrato nella sezione introduttiva riportata sopra. La richiesta utilizza il parametro fields per specificare i campi da restituire.

https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)

La risposta parziale ha il seguente aspetto:

200 OK
{
  "kind": "demo",
  "items": [{
    "title": "First title",
    "characteristics": {
      "length": "short"
    }
  }, {
    "title": "Second title",
    "characteristics": {
      "length": "long"
    }
  },
  ...
  ]
}

Nota: per le API che supportano i parametri di ricerca per l'impaginazione dei dati (ad esempio, maxResults e nextPageToken), utilizza tali parametri per ridurre i risultati di ogni query a una dimensione gestibile. In caso contrario, i miglioramenti delle prestazioni possibili con una risposta parziale potrebbero non essere realizzati.

Patch (aggiornamento parziale)

Puoi anche evitare di inviare dati non necessari quando modifichi le risorse. Per inviare dati aggiornati solo per i campi specifici che stai modificando, utilizza il verbo HTTP PATCH. La semantica delle patch descritta in questo documento è diversa (e più semplice) rispetto all'implementazione GData dell'aggiornamento parziale precedente.

Il breve esempio riportato di seguito mostra come l'uso della patch riduce al minimo i dati che devi inviare per eseguire un piccolo aggiornamento.

Esempio

Questo esempio mostra una semplice richiesta di patch per aggiornare solo il titolo di una risorsa API generica (di fantasia) "Demo". La risorsa contiene anche un commento, un insieme di caratteristiche, lo stato e molti altri campi. Tuttavia, questa richiesta invia solo il campo title, dato che questo è l'unico campo che viene modificato:

PATCH https://www.googleapis.com/demo/v1/324
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "title": "New title"
}

Risposta:

200 OK
{
  "title": "New title",
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "accuracy": "high",
    "followers": ["Jo", "Will"],
  },
  "status": "active",
  ...
}

Il server restituisce un codice di stato 200 OK e la rappresentazione completa della risorsa aggiornata. Poiché solo il campo title è stato incluso nella richiesta di patch, questo è l'unico valore diverso da prima.

Nota: se si utilizza il parametro risposta parziale fields in combinazione con la patch, è possibile aumentare ulteriormente l'efficienza delle richieste di aggiornamento. Una richiesta di patch riduce solo le dimensioni della richiesta. Una risposta parziale riduce le dimensioni della risposta. Per ridurre la quantità di dati inviati in entrambe le direzioni, utilizza una richiesta di patch con il parametro fields.

Semantica di una richiesta di patch

Il corpo della richiesta di applicazione della patch include solo i campi della risorsa che vuoi modificare. Quando specifichi un campo, devi includere tutti gli oggetti padre che li includono, così come vengono restituiti i genitori che contengono una risposta parziale. I dati modificati che invii vengono uniti ai dati dell'oggetto padre, se ne esiste uno.

  • Aggiungi:per aggiungere un campo che non esiste già, specifica il nuovo campo e il relativo valore.
  • Modifica:per modificare il valore di un campo esistente, specifica il campo e impostalo sul nuovo valore.
  • Elimina: per eliminare un campo, specificalo e impostalo su null. Ad esempio: "comment": null. Puoi anche eliminare un intero oggetto (se è modificabile) impostandolo su null. Se utilizzi la libreria client dell'API Java, utilizza Data.NULL_STRING; per i dettagli, consulta JSON null.

Nota sugli array: le richieste di patch che contengono array sostituiscono l'array esistente con quella fornita. Non puoi modificare, aggiungere o eliminare elementi in un array a scaglioni.

Utilizzo della patch in un ciclo di lettura, modifica e scrittura

Può essere utile iniziare recuperando una risposta parziale con i dati che vuoi modificare. Questo è particolarmente importante per le risorse che utilizzano ETag, poiché devi fornire il valore corrente dell'ETag nell'intestazione HTTP If-Match per aggiornare la risorsa. Dopo aver ottenuto i dati, puoi modificare i valori che vuoi modificare e inviare nuovamente la rappresentazione parziale modificata con una richiesta di patch. Ecco un esempio che presuppone che la risorsa demo utilizzi ETag:

GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token

Questa è la risposta parziale:

200 OK
{
  "etag": "ETagString"
  "title": "New title"
  "comment": "First comment.",
  "characteristics": {
    "length": "short",
    "level": "5",
    "followers": ["Jo", "Will"],
  }
}

La seguente richiesta di patch è basata su tale risposta. Come mostrato di seguito, utilizza anche il parametro fields per limitare i dati restituiti nella risposta della patch:

PATCH https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json
If-Match: "ETagString"
{
  "etag": "ETagString"
  "title": "",                  /* Clear the value of the title by setting it to the empty string. */
  "comment": null,              /* Delete the comment by replacing its value with null. */
  "characteristics": {
    "length": "short",
    "level": "10",              /* Modify the level value. */
    "followers": ["Jo", "Liz"], /* Replace the followers array to delete Will and add Liz. */
    "accuracy": "high"          /* Add a new characteristic. */
  },
}

Il server risponde con un codice di stato HTTP 200 OK e la rappresentazione parziale della risorsa aggiornata:

200 OK
{
  "etag": "newETagString"
  "title": "",                 /* Title is cleared; deleted comment field is missing. */
  "characteristics": {
    "length": "short",
    "level": "10",             /* Value is updated.*/
    "followers": ["Jo" "Liz"], /* New follower Liz is present; deleted Will is missing. */
    "accuracy": "high"         /* New characteristic is present. */
  }
}

Creazione diretta di una richiesta di patch

Per alcune richieste di patch, devi basarli sui dati recuperati in precedenza. Ad esempio, se vuoi aggiungere un elemento a un array e non vuoi perdere nessuno degli elementi dell'array esistenti, devi prima recuperare i dati esistenti. Analogamente, se un'API utilizza ETag, devi inviare il valore ETag precedente con la richiesta per aggiornare la risorsa correttamente.

Nota:puoi utilizzare un'intestazione HTTP "If-Match: *" per forzare l'applicazione di una patch quando sono in uso i tag ETag. Se lo fai, non dovrai eseguire la lettura prima della scrittura.

Per altre situazioni, tuttavia, puoi creare la richiesta di patch direttamente senza dover prima recuperare i dati esistenti. Ad esempio, puoi facilmente configurare una richiesta di patch per aggiornare un campo in base a un nuovo valore o aggiungerne uno nuovo. Ecco un esempio:

PATCH https://www.googleapis.com/demo/v1/324?fields=comment,characteristics
Authorization: Bearer your_auth_token
Content-Type: application/json

{
  "comment": "A new comment",
  "characteristics": {
    "volume": "loud",
    "accuracy": null
  }
}

Con questa richiesta, se il campo del commento ha un valore esistente, il nuovo valore lo sovrascriverà; altrimenti, viene impostato sul nuovo valore. Analogamente, se era presente una caratteristica di volume, il relativo valore viene sovrascritto; in caso contrario, viene creato. Il campo relativo alla precisione, se impostato, viene rimosso.

Gestione della risposta a una patch

Dopo l'elaborazione di una richiesta di patch valida, l'API restituisce un codice di risposta HTTP 200 OK insieme alla rappresentazione completa della risorsa modificata. Se i tag ETag vengono utilizzati dall'API, il server aggiorna i valori ETag quando elabora correttamente una richiesta di patch, proprio come fa con PUT.

La richiesta di patch restituisce l'intera rappresentazione della risorsa a meno che non utilizzi il parametro fields per ridurre la quantità di dati restituiti.

Se una richiesta di patch restituisce un nuovo stato della risorsa sintatticamente o semanticamente non valido, il server restituisce un codice di stato HTTP 400 Bad Request o 422 Unprocessable Entity e lo stato della risorsa rimane invariato. Ad esempio, se tenti di eliminare il valore di un campo obbligatorio, il server restituisce un errore.

Notazione alternativa quando il verbo HTTP PATCH non è supportato

Se il firewall non consente le richieste HTTP PATCH, esegui una richiesta HTTP POST e imposta l'intestazione di override su PATCH, come mostrato di seguito:

POST https://www.googleapis.com/...
X-HTTP-Method-Override: PATCH
...

Differenza tra patch e aggiornamento

In pratica, quando invii i dati per una richiesta di aggiornamento che utilizza il verbo HTTP PUT, devi solo inviare i campi obbligatori o facoltativi; se invii valori per i campi impostati dal server, questi verranno ignorati. Anche se potrebbe sembrare un altro modo per eseguire un aggiornamento parziale, questo approccio presenta alcune limitazioni. Con gli aggiornamenti che utilizzano il verbo HTTP PUT, la richiesta non riesce se non fornisci i parametri richiesti e cancella i dati precedentemente impostati se non fornisci i parametri facoltativi.

Per questo motivo è molto più sicuro utilizzare una patch. Fornisci solo i dati per i campi che vuoi modificare; i campi che ometti non vengono cancellati. L'unica eccezione a questa regola si verifica con gli elementi o gli array ripetuti: se ometti tutti i valori, resteranno invariati così come hai fornito tu, se li fornisci, l'intero insieme viene sostituito dall'insieme fornito.