Service Registration
axum
handlers execute in an asynchronous context. This requires that an injected service must be thread-safe. axum
imposes that an such service must implement Send
and Sync
.
Most structures will already satisfy this requirement and is generated by the compiler. If it doesn't, then the struct will have to be wrapped by another struct that satisfies this
requirement. A trait, on the other hand, has several options and depends on the trait definition itself. The method you chose to use is largely based on your preference.
Thread-Safe Trait
A trait declares it is thread-safe if it requires implementing Send
and Sync
.
trait Service: Send + Sync {}
#[injectable(Service)]
struct ServiceImpl;
impl Service for ServiceImpl {}
async fn handler(Inject(service): Inject<dyn Service>) {}
Multiple Trait Implementation
If the original trait does not declare thread safety with Send
and Sync
, then a struct implementation can directly specify that it is thread-safe.
trait Service {}
#[injectable(Service + Send + Sync)]
struct ServiceImpl;
impl Service for ServiceImpl {}
async fn handler(Inject(service): Inject<dyn Service + Send + Sync>) {}
Trait Unification
If the original trait does not declare thread safety with Send
and Sync
, another alterative is to unify the trait with Send
and Sync
in a new trait.
You might chose this approach for better usage ergonomics.
trait Service {}
trait ServiceAsync: Service + Send + Sync {}
#[injectable(ServiceAsync)]
struct ServiceImpl;
impl Service for ServiceImpl {}
impl ServiceAsync for ServiceImpl {}
async fn handler(Inject(service): Inject<dyn ServiceAsync>) {}