Различия между интерфейсом клиента и ресурса в boto3.

Интерфейс клиента и ресурса выглядят очень похоже, но выбор одного вместо другого может иметь серьезные последствия.

Если вы пишете лямбда-функции на Python, вы могли заметить из фрагментов кода в Интернете или примеров, представленных в документации AWS, что одну и ту же работу можно выполнить с помощью boto3.client или boto3.resource. Однако выбор между ними может существенно повлиять на производительность, удобочитаемость и ремонтопригодность вашего кода.

В этой статье мы рассмотрим различия между двумя интерфейсами и дадим советы о том, когда использовать каждый из них.

Прежде чем мы углубимся в эти различия, давайте начнем с самого Boto3:

Boto3 — это название пакета разработки программного обеспечения Python для AWS. SDK — это набор инструментов для создания программного обеспечения, который позволяет разработчикам создавать программные приложения быстрее и более стандартизированным способом. В нашем конкретном случае это дает нам возможность напрямую создавать, обновлять и удалять ресурсы AWS из наших скриптов Python. По сути, все, что делает Boto3, — это вызывает API от вашего имени с помощью методов, доступных для каждого клиента. Существует два разных способа доступа к этим абстрактным API:

Клиент и ресурс.

Теперь, когда мы установили контекст, давайте поговорим о самом существенном различии: их уровне абстракции.

Клиентский интерфейс предлагает доступ к сервису более низкого уровня, соответствующий 1:1 с сервисным API AWS. Если вы использовали CLI для вызова API, вы могли заметить, что синтаксис почти идентичен тому, что используется клиентом, включая допустимые аргументы и параметры. Это связано с тем, что и CLI, и Boto3 построены поверх пакета botocore и работают на более низком уровне. В результате все операции AWS поддерживаются клиентом и доступны вам.
Загвоздка здесь в том, что для работы с Client может потребоваться больше программирования, так как он обычно возвращает ответ словаря, который необходимо проанализировать.

Интерфейс Resource предлагает интерфейс более высокого уровня, обеспечивающий объектно-ориентированный способ работы со службами. Этот интерфейс обычно приводит к более компактному и чистому коду, поскольку многие операции уже выполняются за вас за кулисами. Объектно-ориентированный подход может упростить работу с ресурсами AWS и управление ими, особенно при работе со сложными отношениями между ними.
Однако за это приходится платить не всеми доступными сервисами API. В объектно-ориентированном интерфейсе каждый ресурс представлен классом Python, а для идентификации конкретных ресурсов используются уникальные идентификаторы. Атрибуты используются для доступа и изменения свойств ресурса, а действия используются для выполнения операций над ресурсом.

Теперь, когда мы обсудили различия, давайте рассмотрим несколько примеров, чтобы лучше представить то, что только что было рассмотрено:

В следующем примере перечислены все корзины S3 с использованием boto3.client:

import boto3

s3_client = boto3.client('s3')
response = s3_client.list_buckets()

buckets = [bucket['Name'] for bucket in response['Buckets']]
print(buckets)

Как упоминалось ранее, метод .list_bucket() соответствует синтаксису команды CLI list-bucket. Однако, когда нам нужно проанализировать список возвращенных сегментов, нам нужно выполнить итерацию по словарю с помощью цикла for. Это может привести к более сложному и менее читаемому коду в зависимости от того, чего мы пытаемся достичь. Но также дайте нам больше свободы для манипулирования данными.

Давайте теперь посмотрим на тот же пример с использованием boto3.resource:

import boto3
s3_resource = boto3.resource('s3')

buckets = [bucket.name for bucket in s3_resource.buckets.all()]
print(buckets) 

Даже на простом примере мы можем увидеть снижение сложности нашего кода. После создания экземпляра объекта boto3.resource мы можем легко получить доступ к атрибутам, таким как bucket.name, и действиям, таким как buckets.all(), благодаря к объектно-ориентированному интерфейсу. При анализе списка сегментов мы больше не перебираем словарь; вместо этого мы перебираем итерируемый объект Python.

Мы также можем наблюдать разницу в соглашениях об именах.

Клиент использует нотацию Snake case в качестве соглашения для именования методов, в то время как Resource использует UpperCaseCamelCase, что соответствует соглашению об именах, используемому для классов Python.

Мы можем суммировать различия в следующей таблице:

Что касается сходства, для разбивки на страницы требуется дополнительный код в обоих интерфейсах. Клиент предоставляет метод paginate(), который извлекает несколько страниц или результатов для вызова API. Напротив, использование Resource требует либо циклического, либо рекурсивного вызова функций для получения дополнительных страниц результатов.

Другое сходство заключается в том, что оба интерфейса не выдают примитивных или неупорядоченных данных. С клиентом данные обычно возвращаются в виде словаря, десериализованного из проводного протокола, используемого API (обычно JSON или XML). Ресурс возвращает объект, представленный классом, определенным пакетом SDK. Сами данные обычно упорядочиваются и десериализуются пакетом SDK за кулисами.

Хотя оба интерфейса могут обрабатывать большинство вариантов использования с одинаковым уровнем производительности, существуют некоторые различия в производительности. Клиентский интерфейс может быть быстрее для определенных операций, требующих низкоуровневого контроля над API, таких как пакетные операции или сложная фильтрация. С другой стороны, интерфейс Resource может быть быстрее для операций, включающих несколько ресурсов или сложные отношения между ними, поскольку он может автоматически обрабатывать пакетную обработку и оптимизацию.

При этом в большинстве случаев разница в производительности не должна быть основным фактором при выборе того, какой из них использовать. Вместо этого следует учитывать другие факторы, такие как удобочитаемость кода, ремонтопригодность и простота использования.

Теперь мы можем ответить на вопрос: когда следует использовать одно, а не другое? И ответ, что неудивительно, таков: это зависит от обстоятельств.

Клиент предоставляет более детализированный интерфейс для сервисов AWS, позволяя вам взаимодействовать с отдельными операциями API и извлекать необработанные данные ответов в формате, который ближе к базовым HTTP-запросам и ответам. Это может быть полезно, если вам нужно выполнять сложные или низкоуровневые операции, которые не поддерживаются интерфейсом более высокого уровня, или если вам нужно получить необъектные данные, такие как файлы журналов или параметры конфигурации.

С другой стороны, Resource предоставляет объектно-ориентированный интерфейс более высокого уровня для сервисов AWS, позволяя вам взаимодействовать с объектами Python с помощью методов и свойств. Это может быть более удобным и интуитивно понятным для многих случаев использования и может помочь вам написать более выразительный и удобный для сопровождения код, который легче понять и отладить.

Последнее важное замечание, которое следует учитывать:

по ресурсам boto3 документация:

«Команда Aws Python SDK не собирается добавлять новые функции в интерфейс ресурсов в boto3. Существующие интерфейсы будут продолжать работать в течение всего жизненного цикла boto3. Клиенты могут получить доступ к новым функциям сервиса через клиентский интерфейс».

согласно обсуждению на GitHub:

«Команда boto3 больше не планирует поддерживать обновления интерфейса ресурсов. Это не устаревший интерфейс, он просто больше не получает новых функций и вряд ли будет исправлять нетривиальные ошибки. Интерфейс и функциональность ресурса останутся неизменными в будущем. Он останется в Boto3 и будет работать так же на протяжении всей жизни Boto3».

Я надеюсь, что эта статья помогла вам лучше понять различия и сходства между этими двумя интерфейсами. Если вы заинтересованы в чтении подобного контента, рассмотрите возможность подписаться на меня здесь, на Medium и других платформах.

Спасибо за чтение.