# Sessions with Valkey/Redis

Valkey and Redis can act as storage providers for caching [session data](../advanced/sessions.md#session-data) such as user credentials.

## Valkey & Sessions

Use the `Application`'s Valkey client for Vapor sessions.
The `Application.valkey` property must be set to use this.
See the [`VaporValkey` guide](valkey.md) for more information on configuring and using Valkey with Vapor.

Here's a quick example:

```swift
import Valkey
import Vapor
import VaporValkey

let app = Application.make(.detect)

app.valkey = ValkeyClient(
    .hostname("localhost"),
    eventLoopGroup: app.eventLoopGroup,
    logger: app.logger
)

app.sessions.use(.valkey())
app.middleware.use(app.sessions.middleware)

app.get("set", ":name") { req in
    req.session.data["name"] = req.parameters.get("name")
    return .ok
}

app.get("hello") { req in
    req.session.data["name"] ?? "world"
}
```

## Redis & Sessions

If a custom [`RedisSessionsDelegate`](https://api.vapor.codes/redis/redissessionsdelegate) isn't provided, a default will be used.

### Default Behavior

#### SessionID Creation

Unless you implement the [`makeNewID()`](https://api.vapor.codes/redis/redissessionsdelegate/makenewid()) method in [your own `RedisSessionsDelegate`](#redissessionsdelegate), all [`SessionID`](https://api.vapor.codes/vapor/sessionid) values will be created by doing the following:

1. Generate 32 bytes of random characters
1. base64 encode the value

For example: `Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=`

#### SessionData Storage

The default implementation of `RedisSessionsDelegate` will store [`SessionData`](https://api.vapor.codes/vapor/sessiondata) as a simple JSON string value using `Codable`.

Unless you implement the [`makeRedisKey(for:)`](https://api.vapor.codes/redis/redissessionsdelegate/makerediskey(for:)) method in your own `RedisSessionsDelegate`, `SessionData` will be stored in Redis with a key that prefixes the `SessionID` with `vrs-` (**V**apor **R**edis **S**essions)

For example: `vrs-Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=`

### Registering A Custom Delegate

To customize how the data is read from and written to Redis, register your own `RedisSessionsDelegate` object as follows:

```swift
import Redis

struct CustomRedisSessionsDelegate: RedisSessionsDelegate {
    // implementation
}

app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate()))
```

### RedisSessionsDelegate

> API Documentation: [`RedisSessionsDelegate`](https://api.vapor.codes/redis/redissessionsdelegate)

An object that conforms to this protocol can be used to change how `SessionData` is stored in Redis.

Only two methods are required to be implemented by a type conforming to the protocol: [`redis(_:store:with:)`](https://api.vapor.codes/redis/redissessionsdelegate/redis(_:store:with:)) and [`redis(_:fetchDataFor:)`](https://api.vapor.codes/redis/redissessionsdelegate/redis(_:fetchdatafor:)).

Both are required, as the way you customize writing the session data to Redis is intrinsically linked to how it is to be read from Redis.

#### RedisSessionsDelegate Hash Example

For example, if you wanted to store the session data as a [**Hash** in Redis](https://redis.io/topics/data-types-intro#redis-hashes), you would implement something like the following:

```swift
func redis<Client: RedisClient>(
    _ client: Client,
    store data: SessionData,
    with key: RedisKey
) -> EventLoopFuture<Void> {
    // stores each data field as a separate hash field
    return client.hmset(data.snapshot, in: key)
}
func redis<Client: RedisClient>(
    _ client: Client,
    fetchDataFor key: RedisKey
) -> EventLoopFuture<SessionData?> {
    return client
        .hgetall(from: key)
        .map { hash in
            // hash is [String: RESPValue] so we need to try and unwrap the
            // value as a string and store each value in the data container
            return hash.reduce(into: SessionData()) { result, next in
                guard let value = next.value.string else { return }
                result[next.key] = value
            }
        }
}
```
