pub trait RequestHandler<T: Request>: Send + Sync {
type Error: Error;
// Required method
fn handle<'life0, 'async_trait>(
&'life0 self,
request: T,
) -> Pin<Box<dyn Future<Output = Result<<T as Request>::Response, Self::Error>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}
Expand description
Trait for representing a Request Handler.
See Request for more information about Commands and Queries.
§Examples
use std::sync::Mutex;
use ddd_rs::application::{Command, CommandHandler, Query, QueryHandler};
// Error type for the Fibonacci service.
//
// It is required to implement the `std::error::Error` trait.
#[derive(Debug, PartialEq)]
struct FibonacciError(&'static str);
impl std::fmt::Display for FibonacciError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for FibonacciError {}
// Fibonacci service.
//
// For demonstration purposes, it is implemented as a stateful service.
#[derive(Default)]
struct FibonacciService {
n: Mutex<u32>,
}
impl FibonacciService {
fn set(&self, n: u32) {
let mut current = self.n.lock().unwrap();
*current = n;
}
fn get_next(&self) -> u32 {
let mut current = self.n.lock().unwrap();
let next = Self::fibonacci(*current);
*current = *current + 1;
next
}
fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => Self::fibonacci(n - 1) + Self::fibonacci(n - 2),
}
}
}
// Sets the current 0-based element of the Fibonacci sequence.
//
// `Command`s usually do not return a value, so their `Response` type is automatically `()`.
struct SetFibonacciCommand {
n: u32,
}
impl Command for SetFibonacciCommand {}
#[async_trait::async_trait]
impl CommandHandler<SetFibonacciCommand> for FibonacciService {
type Error = FibonacciError;
async fn handle(&self, command: SetFibonacciCommand) -> Result<(), Self::Error> {
self.set(command.n);
Ok(())
}
}
// Gets the next element of the Fibonacci sequence.
//
// `Query`s are issued in order to retrieve a value, but without causing any side-effects to the
// underlying state of the system.
//
// The more general `Request` trait can be used for actions that have side-effects but also
// require a value to be returned as its result.
struct GetNextFibonacciQuery;
impl Query for GetNextFibonacciQuery {
type Response = u32;
}
#[async_trait::async_trait]
impl QueryHandler<GetNextFibonacciQuery> for FibonacciService {
type Error = FibonacciError;
async fn handle(&self, _query: GetNextFibonacciQuery) -> Result<u32, Self::Error> {
Ok(self.get_next())
}
}
// Finally, instantiate and perform `Request`s to the `FibonacciService`.
let fibonacci = FibonacciService::default();
assert_eq!(fibonacci.handle(SetFibonacciCommand { n: 10 }).await, Ok(()));
assert_eq!(fibonacci.handle(GetNextFibonacciQuery).await, Ok(55));
assert_eq!(fibonacci.handle(GetNextFibonacciQuery).await, Ok(89));
assert_eq!(fibonacci.handle(GetNextFibonacciQuery).await, Ok(144));