# The built-in cache

Store data that is immediately available to every service on every server.

Every service has access to a built-in cache via `self.cache`.

It is backed by Redis, so everything Redis offers is available to your services as well, and the same self.cache has an alias of self.redis as well.

## Set and get a value {#set-and-get-a-value}

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Store a value
        self.cache.set('my-key', 'my-value')

        # Read it back - values come back as bytes
        value = self.cache.get('my-key')
        value = value.decode('utf8')

        self.logger.info(value)
```

```text
INFO - my-value
```

## Set a value with expiry {#set-a-value-with-expiry}

The `ex` parameter is the expiry in seconds - after that, the key is gone and `get` returns None.

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Store a value that expires in 60 seconds
        self.cache.set('session-token', 'abc123', ex=60)

        # Read it back - returns the value if not expired, None otherwise
        value = self.cache.get('session-token')

        self.logger.info(value)
```

```text
INFO - b'abc123'
```

## Cache a dictionary {#cache-a-dictionary}

Dictionaries and lists are serialized to JSON on the way in and parsed on the way out.

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

# stdlib
from json import dumps, loads

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        user_data = {
            'username': 'joe',
            'email': 'joe@example.com',
            'roles': ['admin', 'editor'],
        }

        # Store a dict with a 5-minute expiry
        self.cache.set('user:123', dumps(user_data), ex=300)

        # Read it back as a Python dict
        cached = self.cache.get('user:123')
        cached = loads(cached)

        self.logger.info(cached['username'])
        self.logger.info(cached['roles'])
```

```text
INFO - joe
INFO - ['admin', 'editor']
```

## Delete a key {#delete-a-key}

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        self.cache.set('temp-key', 'temp-value')

        # Delete the key
        self.cache.delete('temp-key')

        # Returns None because the key was deleted
        value = self.cache.get('temp-key')

        self.logger.info(value)
```

```text
INFO - None
```

## Check whether a key exists {#check-whether-a-key-exists}

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        self.cache.set('flag-key', '1', ex=300)

        if self.cache.exists('flag-key'):
            self.logger.info('Key is present')

        self.cache.delete('flag-key')

        if not self.cache.exists('flag-key'):
            self.logger.info('Key is gone')
```

```text
INFO - Key is present
INFO - Key is gone
```

## Cache miss {#cache-miss}

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Returns None when the key does not exist
        value = self.cache.get('my-key')

        if value is None:
            self.logger.info('Key not found, fetching from source ..')
            value = 'value-from-source'
            self.cache.set('my-key', value, ex=120)

        self.logger.info(value)
```

```text
INFO - Key not found, fetching from source ..
INFO - value-from-source
```

## Set only if absent {#set-only-if-absent}

With `nx=True`, the value is stored only when the key does not exist yet, and the call tells you whether it was this call that stored it. Because the cache is shared, this is a single-winner primitive across all services and servers - only one of any number of concurrent callers gets True.

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

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):

        # Only one concurrent caller will store the value and see True
        is_winner = self.cache.set('daily-report-lock', '1', ex=3600, nx=True)

        if is_winner:
            self.logger.info('This invocation runs the report')
        else:
            self.logger.info('Another invocation is already running it')
```

## Beyond caching {#beyond-caching}

Since `self.cache` is a full Redis client, lists, hashmaps, counters and transactions are all available too - the [Redis examples](https://zato.io/docs/dev/examples/redis.html) page shows them, and for locking across servers the platform has purpose-built [distributed locks](https://zato.io/docs/dev/dist-locks.html). Whole channel responses can also be cached declaratively, without any code, with [response caching](https://zato.io/docs/dev/api-management/response-caching.html).

## See also {#see-also}

- [Redis](https://zato.io/docs/dev/examples/redis.html) - Lists, hashmaps and counters behind the same object
- [Distributed locks](https://zato.io/docs/dev/dist-locks.html) - Coordinate work across servers beyond the nx pattern
- [Response caching](https://zato.io/docs/dev/api-management/response-caching.html) - Cache whole channel responses with no code

## 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
