В этом документе рассматриваются некоторые методы повышения производительности вашего приложения. В некоторых случаях для иллюстрации представленных идей используются примеры из других API или универсальных API. Однако те же концепции применимы и к API Gmail.
Сжатие с помощью gzip
Простой и удобный способ сократить пропускную способность, необходимую для каждого запроса, — включить сжатие gzip. Хотя это требует дополнительного процессорного времени для распаковки результатов, компромисс с сетевыми затратами обычно оправдывает себя.
Чтобы получить ответ, закодированный с помощью gzip, необходимо выполнить два действия: установить заголовок Accept-Encoding
и изменить пользовательский агент, добавив строку gzip
. Вот пример правильно сформированных HTTP-заголовков для включения сжатия gzip:
Accept-Encoding: gzip User-Agent: my program (gzip)
Работа с частичными ресурсами
Еще один способ повысить производительность вызовов API — отправлять и получать только ту часть данных, которая вам интересна. Это позволяет приложению избегать передачи, анализа и хранения ненужных полей, что позволяет ему более эффективно использовать ресурсы, включая сеть, ЦП и память.
Существует два типа частичных запросов:
- Частичный ответ : запрос, в котором вы указываете, какие поля следует включить в ответ (используйте параметр запроса
fields
). - Patch : запрос на обновление, при котором вы отправляете только те поля, которые хотите изменить (используйте HTTP-команду
PATCH
).
Более подробная информация о подаче частичных запросов представлена в следующих разделах.
Частичный ответ
По умолчанию сервер отправляет полное представление ресурса после обработки запросов. Для повышения производительности вы можете попросить сервер отправлять только те поля, которые вам действительно нужны, и вместо этого получать частичный ответ .
Чтобы запросить частичный ответ, используйте параметр запроса fields
, чтобы указать поля, которые нужно вернуть. Этот параметр можно использовать с любым запросом, возвращающим данные ответа.
Обратите внимание, что параметр fields
влияет только на данные ответа; он не влияет на данные, которые необходимо отправить, если таковые имеются. Чтобы сократить объём данных, отправляемых при изменении ресурсов, используйте запрос на исправление .
Пример
В следующем примере показано использование параметра fields
с универсальным (вымышленным) «Demo» API.
Простой запрос: этот HTTP-запрос GET
пропускает параметр fields
и возвращает полный ресурс.
https://www.googleapis.com/demo/v1
Полный ответ о ресурсе: Полные данные о ресурсе включают в себя следующие поля, а также многие другие, которые были опущены для краткости.
{ "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", ... }, ... ] }
Запрос частичного ответа: Следующий запрос к этому же ресурсу использует параметр fields
для значительного сокращения объема возвращаемых данных.
https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)
Частичный ответ: в ответ на запрос, указанный выше, сервер отправляет ответ, содержащий только информацию о типе вместе с урезанным массивом элементов, который включает только заголовок HTML и информацию о характеристиках длины для каждого элемента.
200 OK
{ "kind": "demo", "items": [{ "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ] }
Обратите внимание, что ответ представляет собой объект JSON, который включает только выбранные поля и содержащие их родительские объекты.
Далее будут рассмотрены подробности форматирования параметра fields
, а затем — более подробная информация о том, что именно возвращается в ответе.
Сводка синтаксиса параметров полей
Формат значения параметра запроса fields
в некоторой степени основан на синтаксисе XPath. Поддерживаемый синтаксис описан ниже, а дополнительные примеры приведены в следующем разделе.
- Для выбора нескольких полей используйте список, разделенный запятыми.
- Используйте
a/b
для выбора поляb
, вложенного в полеa
; используйтеa/b/c
для выбора поляc
вложенного вb
.Исключение: для ответов API, использующих обёртки "data", где ответ вложен в объект
data
, который выглядит какdata: { ... }
, не включайте "data
" в спецификациюfields
. Включение объекта данных вместе со спецификацией полей, напримерdata/a/b
приведёт к ошибке. Вместо этого используйте просто спецификациюfields
, например,a/b
. - Используйте подселектор для запроса набора определенных подполей массивов или объектов, поместив выражения в скобки «
( )
».Например,
fields=items(id,author/email)
возвращает только идентификатор элемента и адрес электронной почты автора для каждого элемента массива items. Вы также можете указать одно подполе, гдеfields=items(id)
эквивалентноfields=items/id
. - При необходимости используйте подстановочные знаки при выборе полей.
Например:
fields=items/pagemap/*
выбирает все объекты на карте страницы.
Дополнительные примеры использования параметра fields
Примеры ниже содержат описания того, как значение параметра fields
влияет на ответ.
Примечание: Как и все значения параметров запроса, значение параметра fields
должно быть закодировано в URL. Для удобства чтения в примерах в этом документе кодировка не указана.
- Определите поля, которые вы хотите вернуть, или сделайте выбор полей .
- Значение параметра запроса
fields
представляет собой список полей, разделённых запятыми, и каждое поле указывается относительно корня ответа. Таким образом, при выполнении операции со списком ответ представляет собой коллекцию, которая обычно включает массив ресурсов. Если выполняется операция, возвращающая один ресурс, поля указываются относительно этого ресурса. Если выбранное вами поле является массивом (или является его частью), сервер возвращает выбранную часть всех элементов массива.
Вот несколько примеров на уровне коллекций:Примеры Эффект items
Возвращает все элементы массива items, включая все поля в каждом элементе, но не включает другие поля. etag,items
Возвращает как поле etag
, так и все элементы в массиве items.items/title
Возвращает только поле title
для всех элементов массива items.
При возврате вложенного поля ответ включает в себя родительские объекты, которые его содержат. Родительские поля не включают в себя никакие другие дочерние поля, если только они не выбраны явно.context/facets/label
Возвращает только поле label
для всех членов массиваfacets
, который сам по себе вложен в объектcontext
.items/pagemap/*/title
Для каждого элемента массива items возвращает только поле title
(если оно есть) всех объектов, являющихся дочерними элементамиpagemap
.
Вот несколько примеров на уровне ресурсов:Примеры Эффект title
Возвращает поле title
запрошенного ресурса.author/uri
Возвращает подполе uri
объектаauthor
в запрошенном ресурсе.links/*/href
Возвращает поле href
всех объектов, являющихся дочерними элементамиlinks
. - Запросите только части определенных полей, используя подвыборки .
- По умолчанию, если в запросе указаны определённые поля, сервер возвращает объекты или элементы массива целиком. Вы можете указать ответ, включающий только определённые подполя. Это можно сделать, используя синтаксис подвыборки «
( )
», как в примере ниже.Пример Эффект items(title,author/uri)
Возвращает только значения title
иuri
автора для каждого элемента в массиве элементов.
Обработка частичных ответов
После обработки сервером корректного запроса, включающего параметр запроса fields
, он возвращает код статуса HTTP 200 OK
вместе с запрошенными данными. Если параметр запроса fields
содержит ошибку или недействителен по какой-либо другой причине, сервер возвращает код статуса HTTP 400 Bad Request
вместе с сообщением об ошибке, сообщающим пользователю о причине ошибки в выборе полей (например, "Invalid field selection a/b"
).
Вот пример частичного ответа, показанный во вводном разделе выше. В запросе используется параметр fields
для указания возвращаемых полей.
https://www.googleapis.com/demo/v1?fields=kind,items(title,characteristics/length)
Частичный ответ выглядит так:
200 OK
{ "kind": "demo", "items": [{ "title": "First title", "characteristics": { "length": "short" } }, { "title": "Second title", "characteristics": { "length": "long" } }, ... ] }
Примечание: Для API, поддерживающих параметры запросов для пагинации данных (например, maxResults
и nextPageToken
), используйте эти параметры, чтобы уменьшить размер результатов каждого запроса до приемлемого. В противном случае выигрыш в производительности, возможный при частичном ответе, может быть не реализован.
Патч (частичное обновление)
Вы также можете избежать отправки ненужных данных при изменении ресурсов. Чтобы отправлять обновлённые данные только для тех полей, которые вы изменяете, используйте HTTP-команду PATCH
. Семантика патча, описанная в этом документе, отличается (и проще), чем в старой реализации частичного обновления в GData.
Короткий пример ниже показывает, как использование патча минимизирует объем данных, которые необходимо отправить для выполнения небольшого обновления.
Пример
В этом примере показан простой запрос на обновление только заголовка универсального (вымышленного) ресурса API «Demo». Ресурс также содержит комментарий, набор характеристик, статус и множество других полей, но этот запрос отправляет только поле title
, поскольку это единственное изменяемое поле:
PATCH https://www.googleapis.com/demo/v1/324 Authorization: Bearer your_auth_token Content-Type: application/json { "title": "New title" }
Ответ:
200 OK
{ "title": "New title", "comment": "First comment.", "characteristics": { "length": "short", "accuracy": "high", "followers": ["Jo", "Will"], }, "status": "active", ... }
Сервер возвращает код статуса 200 OK
вместе с полным описанием обновлённого ресурса. Поскольку в запрос на исправление было включено только поле title
, это единственное значение, которое отличается от предыдущего.
Примечание: Использование параметра «partical response fields
в сочетании с параметром «patch» позволяет ещё больше повысить эффективность запросов на обновление. Запрос «patch» только уменьшает размер запроса. Частичный ответ уменьшает размер ответа. Поэтому, чтобы сократить объём данных, передаваемых в обоих направлениях, используйте запрос «patch» с параметром « fields
.
Семантика запроса на исправление
Тело запроса на исправление включает только поля ресурсов, которые вы хотите изменить. При указании поля необходимо включить все вложенные родительские объекты, так же как вложенные родительские объекты возвращаются в частичном ответе . Отправляемые вами изменённые данные объединяются с данными родительского объекта, если таковой имеется.
- Добавить: чтобы добавить поле, которое еще не существует, укажите новое поле и его значение.
- Изменить: чтобы изменить значение существующего поля, укажите поле и задайте для него новое значение.
- Удалить: чтобы удалить поле, укажите его и установите для него значение
null
. Например,"comment": null
. Вы также можете удалить весь объект (если он изменяем), установив его вnull
. Если вы используете клиентскую библиотеку Java API , используйте вместо негоData.NULL_STRING
; подробности см. в разделе JSON null .
Примечание о массивах: запросы на исправление, содержащие массивы, заменяют существующий массив предоставленным вами. Вы не можете изменять, добавлять или удалять элементы массива по частям.
Использование патча в цикле чтения-изменения-записи
Может быть полезно начать с получения частичного ответа с данными, которые вы хотите изменить. Это особенно важно для ресурсов, использующих ETag, поскольку для успешного обновления ресурса необходимо указать текущее значение ETag в HTTP-заголовке If-Match
. После получения данных вы можете изменить значения, которые хотите изменить, и отправить изменённое частичное представление обратно с запросом на исправление. Вот пример, в котором предполагается, что ресурс Demo использует ETag:
GET https://www.googleapis.com/demo/v1/324?fields=etag,title,comment,characteristics Authorization: Bearer your_auth_token
Вот частичный ответ:
200 OK
{ "etag": "ETagString" "title": "New title" "comment": "First comment.", "characteristics": { "length": "short", "level": "5", "followers": ["Jo", "Will"], } }
Следующий запрос на исправление основан на этом ответе. Как показано ниже, он также использует параметр fields
для ограничения данных, возвращаемых в ответе на исправление:
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. */ }, }
Сервер отвечает кодом статуса HTTP 200 OK и частичным представлением обновленного ресурса:
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. */ } }
Непосредственное создание запроса на исправление
Для некоторых запросов на исправление необходимо основываться на ранее полученных данных. Например, если вы хотите добавить элемент в массив и не хотите потерять ни одного из его элементов, сначала необходимо получить существующие данные. Аналогично, если API использует ETag, для успешного обновления ресурса необходимо отправить предыдущее значение ETag вместе с запросом.
Примечание: Вы можете использовать HTTP-заголовок "If-Match: *"
, чтобы принудительно выполнить патч при использовании ETag. В этом случае вам не нужно выполнять чтение перед записью.
Однако в других ситуациях вы можете создать запрос на исправление напрямую, без предварительного извлечения существующих данных. Например, вы можете легко настроить запрос на исправление, который обновляет поле новым значением или добавляет новое поле. Вот пример:
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 } }
При таком запросе, если поле комментария имеет существующее значение, новое значение перезаписывает его; в противном случае ему присваивается новое значение. Аналогично, если существовала характеристика объёма, её значение перезаписывается; в противном случае она создаётся. Поле точности, если задано, удаляется.
Обработка ответа на патч
После обработки корректного запроса на исправление API возвращает HTTP-код ответа 200 OK
вместе с полным представлением изменённого ресурса. Если API использует ETag, сервер обновляет значения ETag после успешной обработки запроса на исправление, как это происходит с PUT
.
Запрос на исправление возвращает полное представление ресурса, если только вы не используете параметр fields
для уменьшения объема возвращаемых данных.
Если запрос на исправление приводит к изменению состояния ресурса, которое синтаксически или семантически недопустимо, сервер возвращает код статуса HTTP 400 Bad Request
или 422 Unprocessable Entity
, и состояние ресурса остаётся неизменным. Например, при попытке удалить значение обязательного поля сервер возвращает ошибку.
Альтернативная запись, когда HTTP-команда PATCH не поддерживается
Если ваш брандмауэр не разрешает запросы HTTP PATCH
, выполните запрос HTTP POST
и установите заголовок переопределения на PATCH
, как показано ниже:
POST https://www.googleapis.com/... X-HTTP-Method-Override: PATCH ...
Разница между патчем и обновлением
На практике при отправке данных для запроса на обновление с использованием HTTP-команды PUT
достаточно отправлять только те поля, которые являются либо обязательными, либо необязательными. Если вы отправляете значения для полей, установленных сервером, они игнорируются. Хотя это может показаться ещё одним способом частичного обновления, такой подход имеет некоторые ограничения. При обновлениях с использованием HTTP-команды PUT
запрос завершается ошибкой, если не указаны обязательные параметры, и удаляет ранее заданные данные, если не указаны необязательные параметры.
По этой причине гораздо безопаснее использовать patch. Вы предоставляете данные только для тех полей, которые хотите изменить; поля, которые вы пропустили, не очищаются. Единственное исключение из этого правила — повторяющиеся элементы или массивы: если вы пропустите все элементы, они останутся такими же, как есть; если вы предоставите хотя бы один из них, весь набор будет заменен предоставленным вами набором.