# Receiving files in a service

What each file transfer item contains and what happens when your service refuses a file.

A [schedule](https://zato.io/docs/dev/file-transfer/schedules.html) invokes the service you named once for each file that is ready. The file has already been read by the time your service runs, so there is nothing to download and no connection to obtain - the contents are in the request.

## What the service receives {#what-the-service-receives}

The item is the service's input:

```python
from zato.server.service import Service

class ProcessInvoice(Service):

    def handle(self):

        item = self.request.input

        self.logger.info('%s from %s, %s bytes', item.file_name, item.conn_name, item.size)
```

Everything the item contains:

| Attribute | Notes |
| --- | --- |
| `conn_type` | Which kind of connection the file came from |
| `conn_name` | The name of the connection |
| `schedule_name` | The name of the schedule that picked the file up |
| `directory` | The directory the file was found in |
| `file_name` | The name of the file on its own, without any directories |
| `full_path` | The directory and the name together, the value to log and to quote in an error |
| `size` | The size in bytes, as the directory listing reported it |
| `last_modified` | The modification time, as an ISO-8601 string |
| `data` | The contents, as bytes |

`data` is bytes, always. Text files need decoding, and the encoding is something you know and the file does not say:

```python
from zato.server.service import Service

class ProcessOrders(Service):

    def handle(self):

        item = self.request.input
        text = item.data.decode('utf8')

        for line in text.splitlines():
            self.logger.info(line)
```

## One file, one invocation {#one-file-one-invocation}

Each file is a separate invocation with its own correlation ID, so a directory holding fifty files produces fifty invocations, each visible on its own in the logs and in the dashboard. Nothing batches them together, and your service never receives a list.

The order of files within one run is the order the remote server listed them in, which is not something to depend on. If files have to be processed in a particular order, that order has to come out of their names or their contents.

## Refusing a file {#refusing-a-file}

If your service raises, the file is refused. It is left exactly where it was, it is not moved and it is not deleted, and the next run offers it again. Nothing is ever lost because a service failed.

This is what to do with a file you cannot process - validate it, raise on what is wrong, and leave it there until somebody fixes the file or the code:

```python
from zato.server.service import Service

class ProcessInvoice(Service):

    def handle(self):

        item = self.request.input
        text = item.data.decode('utf8')

        if not text.startswith('INVOICE'):
            raise Exception(f'Not an invoice file: `{item.full_path}`')

        self.logger.info('Taking %s', item.full_path)
```

A file that keeps being refused keeps coming back, run after run, so a permanently bad file is a permanent error in the logs until it is dealt with. If that is not what you want for a given feed, catch the problem in your own service, put the file's contents somewhere for later inspection, and return normally so the file is moved out of the way.

One refused file has no effect on the others. The run continues to the next file and the healthy ones go through as usual.

## Passing the contents on {#passing-the-contents-on}

From here the file is data like any other, and the rest of the platform is available in the usual way - invoke another service, write to a database, publish to a topic, call a REST endpoint:

```python
from zato.server.service import Service

class ProcessInvoice(Service):

    def handle(self):

        item = self.request.input

        # Pass the contents to the service that imports invoices
        self.invoke('billing.import-invoice', {
            'source': item.full_path,
            'received': item.last_modified,
            'data': item.data.decode('utf8'),
        })
```

See [data models](https://zato.io/docs/dev/model/index.html) for declaring the structure of a file's contents, and [data mapping](https://zato.io/docs/dev/rest/data-mapping.html) for converting between formats.

A file that is a zip archive, or an [IHE XDM package](https://zato.io/docs/dev/healthcare/xdm/index.html) of clinical documents, is read with `item.documents()` - each file inside the archive is returned as a document with its name, MIME type and bytes, and a file that is not an archive is returned as the one document it is, so a service handles both without telling them apart.

## Related {#related}

- [File transfer schedules](https://zato.io/docs/dev/file-transfer/schedules.html) - when and how often your service is invoked
- [Real-world feeds](https://zato.io/docs/dev/file-transfer/feeds.html) - the arrangements these services are part of

## Learn more {#learn-more}

- [File transfer](https://zato.io/docs/dev/file-transfer/) - SFTP, FTP and SMB behind one API, driven by your code or by a schedule
- [The connection API](https://zato.io/docs/dev/file-transfer/connection-api.html) - Upload, download, read, write, list and manage remote entries
- [Schedules](https://zato.io/docs/dev/file-transfer/schedules.html) - Have Zato watch a remote directory and invoke a service per file
- [Real-world feeds](https://zato.io/docs/dev/file-transfer/feeds.html) - Marker files, archiving, bad files and pausing a feed
- [File transfer in enmasse](https://zato.io/docs/dev/file-transfer/enmasse.html) - Connections and schedules as YAML, ready for version control
