libero/remote_data
Typed states for async data loading. Inspired by Elm’s RemoteData package.
Use instead of Bool flags + Option fields for data that loads asynchronously. The view pattern matches directly on the state - impossible to show stale data while loading or forget to handle errors.
Generated RPC stubs build RpcData directly: the per-endpoint
decode_response_<fn> FFI returns an RpcData(payload, domain) that
the page stores in its model. NotAsked and Loading are page-lifecycle
states the page sets itself in init and update. Failure carries
either a TransportError(RpcError) (framework / wire-level) or a typed
DomainError(domain) from the handler’s own error type.
Types
pub type RemoteData(value, error) {
NotAsked
Loading
Failure(error)
Success(value)
}
Constructors
-
NotAsked -
Loading -
Failure(error) -
Success(value)
Convenience alias for RemoteData pinned to RpcOutcome. Mirrors
Elm’s WebData a = RemoteData Http.Error a. Callers write
RpcData(List(Todo), TodoError) instead of
RemoteData(List(Todo), RpcOutcome(TodoError)).
pub type RpcData(value, domain) =
RemoteData(value, RpcOutcome(domain))
Composite error for an RPC outcome. Keeps transport-level failures
(framework errors, version skew, malformed responses) typed as
RpcError while preserving the caller’s typed domain error from
the handler. Lets view code pattern-match on the tier it cares
about, or fall through with Failure(_) for a generic message.
pub type RpcOutcome(domain) {
TransportError(error.RpcError)
DomainError(domain)
}
Constructors
-
TransportError(error.RpcError) -
DomainError(domain)
Values
pub fn fold(
data data: RemoteData(a, e),
on_not_asked on_not_asked: fn() -> b,
on_loading on_loading: fn() -> b,
on_failure on_failure: fn(e) -> b,
on_success on_success: fn(a) -> b,
) -> b
Reduce all four states into a single value. Each case provides its
own callback so the caller can return whatever shape they need
(e.g. an Element(msg) for a Lustre view).
pub fn format_failure(
outcome outcome: RpcOutcome(domain),
format_domain format_domain: fn(domain) -> String,
) -> String
Render an RpcOutcome as a single user-facing string. The caller
supplies a formatter for their domain error type; transport errors
are routed through format_transport_error.
Use this anywhere two arms differ only by which formatter runs. In views:
Failure(outcome) -> render(format_failure(outcome, format_my_error))
In an update reducer that surfaces a flash message:
LoadResult(Failure(outcome)) -> #(
model,
effect.none(),
Some(#(Danger, format_failure(outcome, format_my_error))),
)
The match becomes exhaustive over RpcOutcome, so no
Failure(_) catch-all is needed and the per-tier DomainError(err) /
TransportError(rpc_err) arms collapse into one.
pub fn format_transport_error(err: error.RpcError) -> String
Default formatter for framework-level transport errors. Useful when
the caller wants a single string for RpcError values rather than
pattern-matching each variant.
pub fn map(
data data: RemoteData(a, e),
transform transform: fn(a) -> b,
) -> RemoteData(b, e)
Apply a function to the success value.
pub fn map_error(
data data: RemoteData(a, e1),
transform transform: fn(e1) -> e2,
) -> RemoteData(a, e2)
Apply a function to the error value.
pub fn to_option(data: RemoteData(a, e)) -> option.Option(a)
Convert to Option - Some for Success, None for everything else.
pub fn unwrap(
data data: RemoteData(a, e),
default default: a,
) -> a
Extract the success value, or return a default.