Amazon::S3::Lite - A lightweight Amazon S3 client for common operations
use Amazon::S3::Lite;
# Credentials from environment or IAM role automatically
my $s3 = Amazon::S3::Lite->new({ region => 'us-east-1' });
# Explicit credentials
my $s3 = Amazon::S3::Lite->new({
region => 'us-east-1',
aws_access_key_id => $key,
aws_secret_access_key => $secret,
token => $session_token, # optional, for STS/Lambda roles
});
# Pass any credentials object with standard getters
my $s3 = Amazon::S3::Lite->new({
region => 'us-east-1',
credentials => $creds_obj,
});
# List objects in a bucket
my $result = $s3->list_objects_v2('my-bucket', prefix => 'logs/');
foreach my $obj ( @{ $result->{objects} } ) {
printf "%s %d bytes\n", $obj->{key}, $obj->{size};
}
# Paginate
while ( $result->{is_truncated} ) {
$result = $s3->list_objects_v2('my-bucket',
prefix => 'logs/',
continuation_token => $result->{next_continuation_token},
);
# ... process $result->{objects}
}
# Get an object
my $obj = $s3->get_object('my-bucket', 'path/to/key.json');
print $obj->{content};
# Head an object (existence check / metadata only)
my $meta = $s3->head_object('my-bucket', 'path/to/key.json');
if ($meta) {
print $meta->{content_length};
}
# Put an object
$s3->put_object('my-bucket', 'path/to/key.json', $json_string,
content_type => 'application/json',
metadata => { source => 'lambda' },
);
# Copy an object
$s3->copy_object(
src_bucket => 'my-bucket', src_key => 'orig/file.json',
dst_bucket => 'my-bucket', dst_key => 'archive/file.json',
);
# Delete an object
$s3->delete_object('my-bucket', 'path/to/key.json');
# List all buckets
my $result = $s3->list_buckets;
for my $bucket ( @{ $result->{buckets} } ) {
print $bucket->{name}, "\n";
}
Amazon::S3::Lite is a minimal Amazon S3 client covering the
operations most commonly needed in AWS Lambda functions and
lightweight scripts: listing buckets, listing objects, reading,
writing, copying, and deleting.
It is built on HTTP::Tiny (core since Perl 5.14) and AWS::Signature4, with no dependency on LWP or any part of the libwww-perl ecosystem. The dependency list is intentionally small, making it well-suited for Lambda container images where minimizing cold-start time and image size matters.
It is not a replacement for Amazon::S3 or Net::Amazon::S3, which support the full S3 API surface including multipart upload, bucket management, ACLs, versioning, and presigned URLs. If you need those features, use one of those distributions instead.
Amazon::S3::Thin is another excellent lightweight S3 client with a
similar philosophy and a longer track record. It is more complete than
this module - supporting presigned URLs, bulk delete, and
virtual-hosted-style requests - and returns raw HTTP::Response
objects so callers handle status codes and errors
themselves. Amazon::S3::Lite differs in three ways: it has no
dependency on LWP (Amazon::S3::Thin defaults to LWP::UserAgent),
it returns parsed hashrefs rather than raw response objects, and it
has first-class support for Lambda IAM role credential rotation. If
you need the broader feature set or prefer direct HTTP access,
Amazon::S3::Thin is a fine choice.
my $s3 = Amazon::S3::Lite->new(\%options);
Returns a new Amazon::S3::Lite object. Options:
region (required)
The AWS region for your bucket, e.g. us-east-1.
aws_access_key_id / aws_secret_access_key
Static credentials. token may also be supplied for STS temporary
credentials (as used by Lambda execution roles).
These are only consulted if no credentials object is provided.
token
Optional STS session token, used alongside static credentials for temporary credential sets.
credentials
An object providing credential getters. The object must respond to:
$creds->aws_access_key_id
$creds->aws_secret_access_key
$creds->token # may return undef
Any object that satisfies this interface is accepted - Amazon::Credentials, Paws::Credential::*, or your own. The getters are called at request time, so objects that refresh expiring credentials transparently are supported.
logger
An object providing the standard log methods:
$logger->trace(...)
$logger->debug(...)
$logger->info(...)
$logger->warn(...)
$logger->error(...)
If not supplied, the module looks for Log::Log4perl. If available,
it calls Log::Log4perl::easy_init with level WARN and logs to
STDERR. If Log::Log4perl is not installed, a minimal internal logger
is used that prints WARN and above to STDERR.
host
Override the S3 endpoint host. Defaults to s3.amazonaws.com.
Useful for S3-compatible services (MinIO, Ceph, LocalStack).
secure
Use HTTPS. Default is 1 (true). Set to 0 only for testing against local S3-compatible endpoints.
timeout
HTTP request timeout in seconds. Default is 30.
When no credentials object is passed, credentials are resolved in
this order:
aws_access_key_id and aws_secret_access_key.AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
and optionally AWS_SESSION_TOKEN.~/.aws/credentials
profiles.All methods croak on unrecoverable errors (network failure, HTTP 5xx).
HTTP 404 is not an exception - methods that can meaningfully return
undef for a missing resource do so.
my $result = $s3->list_objects_v2($bucket, %options);
Lists objects in $bucket using the S3 ListObjectsV2 API.
Options:
prefix
Limit results to keys beginning with this string.
delimiter
Group keys sharing a common prefix up to this delimiter. Grouped
prefixes are returned in common_prefixes.
max_keys
Maximum number of objects to return per call (1-1000, default 1000).
continuation_token
Resume a truncated listing from a prior call's
next_continuation_token.
start_after
Return only keys lexicographically after this value.
Returns a hashref:
{
bucket => 'my-bucket',
prefix => 'logs/',
is_truncated => 0,
next_continuation_token => undef, # set when is_truncated is true
key_count => 42,
objects => [
{
key => 'logs/2024-01-01.gz',
size => 102400,
last_modified => '2024-01-01T00:00:00.000Z',
etag => 'abc123',
storage_class => 'STANDARD',
},
...
],
common_prefixes => [], # populated when delimiter is set
}
my @objects = $s3->list_all_objects_v2($bucket, %options);
Convenience wrapper around "list_objects_v2" that automatically follows continuation tokens and returns a flat list of all matching object hashrefs in a single call.
Accepts the same options as list_objects_v2 except
continuation_token (which is managed internally) and delimiter
(which is silently ignored - see below).
my @logs = $s3->list_all_objects_v2('my-bucket', prefix => 'logs/');
foreach my $obj (@logs) {
printf "%s %d bytes\n", $obj->{key}, $obj->{size};
}
Be mindful of memory when listing buckets with large numbers of objects. For very large listings, use "list_objects_v2" directly and process each page as it arrives.
delimiter and common_prefixes are not supported by this method.
The purpose of list_all_objects_v2 is a complete flat listing of
all matching keys. Hierarchical directory-style traversal using
delimiter is inherently page-by-page and should use
"list_objects_v2" directly.
Returns a (possibly empty) list of object hashrefs, each with the same
fields as the elements of objects in the list_objects_v2
response.
my $obj = $s3->get_object($bucket, $key);
my $obj = $s3->get_object($bucket, $key, %options);
Fetches the object at $key in $bucket.
Returns undef if the key does not exist (HTTP 404).
Returns a hashref on success:
{
content => '...', # raw bytes; absent when filename is used
content_type => 'application/json',
content_length => 1024,
etag => 'abc123',
last_modified => 'Tue, 01 Jan 2024 00:00:00 GMT',
metadata => { # x-amz-meta-* headers, lowercased
source => 'lambda',
},
}
Options:
range
An HTTP Range header value, e.g. bytes=0-1023, for partial fetches.
filename
Path to a local file where the object body should be written. When
supplied, the response body is streamed directly to disk via
HTTP::Tiny's :content_file mechanism and content is omitted from
the returned hashref. The file is created or overwritten.
my $meta = $s3->get_object('my-bucket', 'data/dump.csv',
filename => '/tmp/dump.csv',
);
# $meta->{content} is absent; file is on disk
This is the recommended approach for large objects in Lambda where holding the full body in memory is undesirable.
my $meta = $s3->head_object($bucket, $key);
Fetches metadata for $key without retrieving the object body.
Useful for existence checks and reading x-amz-meta-* headers
cheaply.
Returns undef if the key does not exist (HTTP 404).
Returns a hashref on success with the same fields as get_object
except content, which is always absent.
$s3->put_object($bucket, $key, $data, %options);
Stores $data at $key in $bucket. $data may be:
When passing a filehandle, content_length becomes required unless
HTTP::Tiny can determine the size from the handle (i.e. the handle is
backed by a real file). For in-memory handles (IO::Scalar, etc.)
you must supply content_length explicitly, or the method will
croak.
# Scalar
$s3->put_object('my-bucket', 'hello.txt', 'Hello, world!',
content_type => 'text/plain',
);
# Filehandle
open my $fh, '<', '/tmp/data.csv' or die $!;
$s3->put_object('my-bucket', 'data.csv', $fh,
content_type => 'text/csv',
);
Options:
content_type
MIME type for the object. Defaults to application/octet-stream.
content_length
Required when $data is an in-memory filehandle. Optional (and
ignored) for scalar data, where length is computed automatically.
metadata
Hashref of user-defined metadata. Keys should be bare names - the
x-amz-meta- prefix is added automatically.
metadata => { source => 'lambda', job_id => '42' }
acl
Canned ACL string, e.g. private (default), public-read.
Returns the ETag of the stored object on success. Croaks on failure.
$s3->copy_object(
src_bucket => 'src-bucket',
src_key => 'original/key.json',
dst_bucket => 'dst-bucket',
dst_key => 'copy/key.json',
);
Copies an object within or between buckets without transferring data through the client. The copy is performed entirely server-side by S3.
Returns a hashref on success:
{
etag => 'abc123',
last_modified => '2024-01-01T00:00:00.000Z',
}
Croaks on failure.
$s3->delete_object($bucket, $key);
$s3->delete_object($bucket, $key, version_id => $vid);
Deletes the object at $key in $bucket.
If version_id is provided, that specific version is deleted.
Returns true on success. Note that S3 returns HTTP 204 for both successful deletes and deletes of non-existent keys, so this method does not distinguish between the two - it succeeds silently in either case.
my $result = $s3->list_buckets;
Lists all S3 buckets owned by the authenticated account.
Returns a hashref:
{
owner_id => 'abc123...',
owner_name => 'myaccount',
buckets => [
{ name => 'my-bucket', creation_date => '2024-01-01T00:00:00.000Z' },
{ name => 'other-bucket', creation_date => '2024-06-01T00:00:00.000Z' },
...
],
}
Note that this operation is always signed against us-east-1
regardless of the region the object was constructed with. See
"LAMBDA USAGE NOTES".
Methods croak on:
Methods return undef on:
All other HTTP error codes (400, 403, 409, etc.) cause a croak with a message containing the HTTP status line and the S3 error body where available.
Optional:
In a Lambda container, credentials come from the execution role via
the ECS credential provider endpoint (indicated by
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI in the environment).
Amazon::Credentials handles this automatically when installed and
is the recommended approach. If you prefer not to take that
dependency, the Lambda runtime also populates AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN directly, which
this module picks up automatically from the environment.
Region note: The list_buckets method is a global S3 operation
and is always signed against us-east-1, regardless of the region
supplied to the constructor. This is an S3 requirement, not a
limitation of this module, and is handled transparently - your
object's region is not changed.
Cold start: Because this module depends only on HTTP::Tiny (Perl core), XML::Twig, AWS::Signature4, and URI::Escape, it adds minimal overhead to Lambda container image builds compared to LWP-based S3 clients.
When testing against LocalStack, be aware that LocalStack is more
lenient than real S3 regarding SigV4 requirements. In particular,
LocalStack may accept requests where the x-amz-content-sha256
header is missing or where session token handling is incorrect. Tests
that pass against LocalStack should always be verified against real S3
before release.
Amazon::S3 - the full-featured S3 client this module draws from
Amazon::S3::Thin - another excellent lightweight S3 client with a similar philosophy, broader feature coverage, and a longer track record. Uses LWP by default and returns raw HTTP::Response objects. See "DESCRIPTION" for a detailed comparison.
Net::Amazon::S3 - a Moose-based full-featured alternative
Amazon::Signature4::Lite - the signing module used internally
Amazon::Credentials - credential provider with IAM role and profile support
Rob Lauer rlauer@treasurersbriefcase.com
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.