Trait RequestHandler

Source
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));

Required Associated Types§

Source

type Error: Error

Request handler error type.

Required Methods§

Source

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,

Handles the incoming Request, returning its Response as a Result.

Implementors§