Serialization
Sury
Sury is the serialization library used by Reventless for JSON encoding and decoding using a PPX.
Basic Usage
@schema annotation
The library automatically generates schema functions for annotated types. The framework relies on these schemas and uses them internally for serialization and deserialization.
Basic Types
@schema
type userId = string
@schema
type count = int
Records
@schema
type countsState = {
id: string,
count: int,
}
@schema
type referencesState = {
id: string,
inc: int,
}
Common Patterns
Variants
Simple variants for enums:
@schema
type effect = Allow | Deny
Complex variants with data:
@schema
type command =
| Heartbeat
| Connect(pluginDefinition)
| Disconnect
| Activate
| Deactivate
@schema
type event =
| UnknownPluginDetected
| Connected(pluginDefinition)
| Disconnected(pluginDefinition)
| Activated(pluginDefinition)
| Deactivated(pluginDefinition)
Key Annotations
Custom JSON field names with @as
@schema
type principal = {
@as("AWS") aws?: string,
@as("Service") service?: string,
}
Unboxed variants with @unboxed
@schema @unboxed
type actions = | @as("*") AllActions | Action(string)
Framework Integration
Framework Internal
This section describes how Reventless uses Sury schemas internally. Most developers won't need to use these functions directly.
Generated Schema Functions
For each @schema annotated type, Sury generates:
- A schema object (e.g.,
countsStateSchema) - Encoding/decoding functions accessible through
Message.encodeandMessage.decode
Serialization Usage
The framework uses these patterns for serialization:
// Encoding data to JSON
let json = state->Message.encode(countsStateSchema)
// Decoding JSON to typed data
switch jsonData->Message.decode(countsStateSchema) {
| {id, count} => // Handle decoded data
| exception _ => // Handle decode errors
}
Practical Example
From the Counter component:
@schema
type countsState = {
id: string,
count: int,
}
// Usage in callback handler
counts->Array.filterMap(state =>
switch state->Message.decode(countsStateSchema) {
| {id, count} if count == 0 =>
// Process completed counter
Some(processCounterEvent(id, count))
| {id, count} =>
// Log current state
Js.log(`Counter ${id} at ${count->Int.toString}`)
None
| exception _ =>
Js.log("Failed to decode counter state")
None
}
)
warning
Any type referenced from inside an annotated type needs to either be a built-in type or another annotated type. The compiler will error otherwise.