AWS Python SDK: Boto3 Client vs Resource

AWS Python SDK: Boto3 Client vs Resource

AWS provides SDKs for many popular technologies and programming languages. They make it easier for us to call AWS services from within our applications in that language or technology.

AWS SDK for Python is composed of two key Python packages: Botocore (the library providing the low-level functionality shared between the Python SDK and the AWS CLI) and Boto3 (the package implementing the Python SDK itself).

While using Python SDK, Client and Resource are two different abstractions within the boto3 SDK for making AWS service requests. When we want to make API calls to an AWS service with boto3, then we do so via a Client or a Resource.

We would typically choose to use either the Client abstraction or the Resource abstraction, but we can use both, as needed. Below is an outlined difference to help readers decide which/when to use.

Here's some more detailed information on what Client, Resource according to AWS Python SDK Boto3 Documentation.

Boto Client:

Clients provide a low-level interface to AWS whose methods map close to 1:1 with service APIs. All service operations are supported by clients. Clients are generated from a JSON service definition file.

In summary:

  1. This is the original boto3 API abstraction

  2. It provides low-level AWS service access

  3. All AWS service operations are supported by clients

  4. It exposes botocore client to the developer

  5. It typically maps 1:1 with the AWS service API

  6. It exposes snake-cased method names (e.g. ListBuckets API => list_buckets method)

  7. Typically yields primitive, non-marshalled data (e.g. DynamoDB attributes are dicts representing primitive DynamoDB values)

  8. Requires you to code result pagination

  9. It is generated from an AWS service description

Here's an example of client-level access to an S3 bucket's objects:

import boto3 

client = boto3.client('s3') 
response = client.list_objects_v2(Bucket='mybucket') 

for content in response['Contents']: 
    obj_dict = client.get_object(Bucket='mybucket', Key=content['Key'])
    print(content['Key'], obj_dict['LastModified'])

Note: this client-level code is limited to listing at most 1000 objects. You would have to use a paginator, or implement your own loop, calling list_objects_v2() repeatedly with a continuation marker if there were more than 1000 objects.

Boto Resource:

Resources represent an object-oriented interface to Amazon Web Services (AWS). They provide a higher-level abstraction than the raw, low-level calls made by service clients. To use resources, you invoke the resource() method of a Session and pass in a service name:

In summary:

  1. This is the newer boto3 API abstraction

  2. It provides a high-level, object-oriented API

  3. It does not provide 100% API coverage of AWS services

  4. It uses identifiers and attributes

  5. It has actions (operations on resources)

  6. It exposes sub-resources and collections of AWS resources

  7. Typically yields marshaled data, not primitive AWS data (e.g. DynamoDB attributes are native Python values representing primitive DynamoDB values)

  8. Does result pagination for you

  9. It is generated from an AWS resource description

Here's the equivalent example using resource-level access to an S3 bucket's objects:

import boto3 

s3 = boto3.resource('s3') 
bucket = s3.Bucket('mybucket') 
for obj in bucket.objects.all(): 
    print(obj.key, obj.last_modified)

Note: in this case you do not have to make a second API call to get the objects; they're available to you as a collection on the bucket. These collections of sub-resources are lazily-loaded.

You can see that the Resource version of the code is much simpler, more compact, and has more capability (for example it does pagination for you and it exposes properties instead of a raw dictionary). The Client version of the code would actually be more complicated than shown above if you wanted to include pagination.