# AWS S3

S3 buckets and objects, presigned URLs and S3-compatible stores from Python services.

Zato lets you work with Amazon S3 directly from your Python services. You create an [AWS connection](https://zato.io/docs/dev/examples/cloud/aws/index.html) in the Dashboard, and the S3 client is available under `conn.s3` - the same client that `boto3.client('s3')` returns, with credentials and configuration managed for you.

## Storing and reading objects {#storing-and-reading-objects}

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class CreateInvoiceBackup(Service):

    input = 'invoice_id', 'data'

    def handle(self):

        # Get the connection by its Dashboard name
        conn = self.aws['My AWS']

        # Store an object in S3
        conn.s3.put_object(
            Bucket='invoices',
            Key=self.request.input.invoice_id,
            Body=self.request.input.data,
        )

        # Read it back
        response = conn.s3.get_object(Bucket='invoices', Key=self.request.input.invoice_id)
        self.response.payload = response['Body'].read()
```

## Listing buckets and objects {#listing-buckets-and-objects}

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class ListInvoices(Service):

    def handle(self):

        conn = self.aws['My AWS']

        # All the buckets the credentials can see
        buckets = conn.s3.list_buckets()

        # All the objects under a prefix in one bucket
        response = conn.s3.list_objects_v2(Bucket='invoices', Prefix='2026/')

        names = []
        for item in response['Contents']:
            names.append(item['Key'])

        self.response.payload = {'names': names}
```

## Deleting objects {#deleting-objects}

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class DeleteInvoice(Service):

    input = 'invoice_id'

    def handle(self):

        conn = self.aws['My AWS']

        conn.s3.delete_object(Bucket='invoices', Key=self.request.input.invoice_id)
```

## Presigned URLs {#presigned-urls}

Presigned URLs let external clients download or upload a specific object for a limited time, without having AWS credentials of their own.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class GetInvoiceDownloadLink(Service):

    input = 'invoice_id'

    def handle(self):

        conn = self.aws['My AWS']

        # A download link that expires after one hour
        url = conn.s3.generate_presigned_url(
            'get_object',
            Params={'Bucket': 'invoices', 'Key': self.request.input.invoice_id},
            ExpiresIn=3600,
        )

        self.response.payload = {'url': url}
```

## S3-compatible stores {#s3-compatible-stores}

The connection's optional "Endpoint URL" field lets you point the same code at any S3-compatible object store instead of AWS - fill it in with the store's address and everything else stays the same.

## More resources {#more-resources}

- [AWS integrations overview](https://zato.io/docs/dev/examples/cloud/aws/index.html)
- [AWS tutorial](https://zato.io/docs/dev/examples/cloud/aws/tutorial.html)
- [boto3 S3 reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - The complete reference for writing services
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how both are structured
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
