Messaging
A Redis connection wrapper that validates JSON payloads on write and on read.

vld-redis wraps a sync or async Redis connection. Values are validated and stored as JSON on write, and decoded and validated on read.

Install

Cargo.toml
[dependencies]
vld = "0.5"
vld-redis = "0.5"  # redis 0.x (>=0.32) by default

The selected redis crate is re-exported as vld_redis::redis, so you do not need a separate dependency.

Features

FeatureDefaultEffect
redis-0yesredis >=0.32, <1
redis-1redis 1.x
aioAsyncRedisConn over redis::aio::ConnectionLike
aio-tokioaio plus redis' tokio support (tokio-comp)

Exactly one of redis-0 / redis-1 must be enabled. redis refuses to compile aio without a runtime: use aio-tokio, or enable aio together with a runtime feature (smol-comp, …) on your own redis dependency of the same version.

vld-redis = { version = "0.5", default-features = false, features = ["redis-1", "aio-tokio"] }

MSRV: 1.85 (see MSRV).

Example

use vld_redis::prelude::*;
use vld_redis::redis;

vld::schema! {
    #[derive(Debug, serde::Serialize)]
    pub struct UserSchema {
        pub name: String => vld::string().min(1).max(100),
        pub email: String => vld::string().email(),
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = redis::Client::open("redis://127.0.0.1/")?;
    let mut conn = RedisConn::new(client.get_connection()?);

    let alice = UserSchema { name: "Alice".into(), email: "alice@example.com".into() };
    conn.set("user:1", &alice)?;
    let loaded: Option<UserSchema> = conn.get("user:1")?;
    assert_eq!(loaded.unwrap().email, "alice@example.com");

    let bad = UserSchema { name: "".into(), email: "nope".into() };
    assert!(matches!(conn.set("user:2", &bad), Err(VldRedisError::Validation(_))));
    Ok(())
}

API

  • RedisConn<C> — sync wrapper over redis::ConnectionLike; new, into_inner, Deref / DerefMut to the connection.
  • AsyncRedisConn<C> (aio) — the same methods, async, over redis::aio::ConnectionLike.
  • Validating commands: set / get, mset / mget, hset / hget, lpush / rpush / lpop / rpop, sadd / smembers, zadd / zrange, publish.
  • VldRedisError — Validation, Serialization, Deserialization, Redis(RedisError).

Gotchas

  • The value type is the schema. Written values must be Serialize + VldParse (a schema! struct with #[derive(serde::Serialize)]); read values are parsed with VldParse.
  • The wrapper's methods shadow redis::Commands / redis::AsyncCommands. conn.get(k) is always the validating JSON get. Commands without a validating version (del, expire, incr, …) go through Deref. To call the native one, use the trait on the inner connection:
    let raw: Option<String> = redis::Commands::get(&mut *conn, "key")?;
    
  • A stored value that is not valid JSON fails with Deserialization; valid JSON that fails the schema fails with Validation.