Serde
The eridu-tech/serde component provides seamless way to serialize/deserialize data and adding custom serialization/deserialization logic for custom data types.
Initial configuration
import { Serde } from "eridu-tech/serde";
import { SuperJsonSerdeAdapter } from "eridu-tech/serde/super-json-serde-adapter";
export const serde = new Serde(new SuperJsonSerdeAdapter());
Serde basics
Serializing and deserializing values
Here is an example of serializing and deserializing a value.
import { serde } from "./serde-initial-config.js";
const serializedValue = serde.serialize({
name: "abra",
age: 20,
});
const deserializedValue = serde.deserialize(serializedValue);
Custom serialization and deserialization logic
The registerCustom method offers control over serialization and deserialization behavior.
import type { ISerdeTransformer } from "eridu-tech/serde/contracts";
import { serde } from "./serde-initial-config.js";
type ISerializedUser = {
version: "1";
name: string;
age: number;
};
class User {
static readonly serdeTransformer: ISerdeTransformer<User, ISerializedUser> =
{
name: "User",
isApplicable(value: unknown): value is User {
return value instanceof User;
},
deserialize(serializedValue: ISerializedUser): User {
return new User(serializedValue.name, serializedValue.age);
},
serialize(deserializedValue: User): ISerializedUser {
return {
version: "1",
name: deserializedValue.name,
age: deserializedValue.age,
};
},
};
constructor(
readonly name: string,
readonly age: number,
) {}
}
serde.registerCustom(User.serdeTransformer);
Note the ISerdeTranformer object can be dynamically created.
Patterns
Usage with other components
When using Serde class instance there is no need to call serialize and deserialize manually. Because components like Cache handle it automatically through their adapter.
import { Serde } from "eridu-tech/serde";
import { SuperJsonSerdeAdapter } from "eridu-tech/serde/super-json-serde-adapter";
import { RedisCacheAdapter } from "eridu-tech/cache/redis-cache-adapter";
import { Cache } from "eridu-tech/cache";
import { ListCollection } from "eridu-tech/collection";
import type { ICollection } from "eridu-tech/collection/contracts";
import { Redis } from "ioredis";
const serde = new Serde(new SuperJsonSerdeAdapter());
serde.registerCustom(ListCollection.serdeTransformer);
const cache = new Cache<ICollection<string>>({
adapter: new RedisCacheAdapter({
database: new Redis("YOUR_REDIS_CONNECTION_STRING"),
serde,
}),
});
const listCollection = new ListCollection(["a", "b", "c", "d", "e"]);
await cache.add("list", listCollection);
const deserializedListCollection = await cache.get("list");
if (deserializedListCollection) {
// Logs "c"
console.log(deserializedListCollection.getOrFail(2));
}
Note you should use one Serde class instance accross all components and register all serializable objects before component usage.
Separating serialization, deserialization and registering custom serialization/deserialization logic
The library includes 4 additional contracts:
-
ISerializer- Allows only for serialization. -
IDeserializer- Allows only for deserialization. -
ISerde- Allows for both serialization and deserialization. -
ISerderRegister- Allows only for registering custom serialization/deserialization logic. -
IFlexibleSerde– Allows for both serialization, deserialization and for registering custom serialization/deserialization and deserialization logic.
This separation makes it easy to visually distinguish the 4 contracts, making it immediately obvious that they serve different purposes.
Further information
For further information refer to eridu-tech/serde API docs.