I'm trying to learn more about how actix web works and I'm the point where I want to create a middleware. Ultimately I want to create a db connection in the middleware and I'm trying to figure out how to get the connection details to the middleware. I've broken the problem down into a small a sample as I could.
// main.rs
// Data I'd want to share would go here
pub struct Data {
pub color: String
}
impl Data {
pub async fn new() -> Arc<Self> {
let data = Data { color: "red".to_string() };
Arc::new(data)
}
}
// MIDDLEWARE
pub struct MyData;
impl<S, B> Transform<S, ServiceRequest> for MyData
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = MyDataMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(MyDataMiddleware { service })
}
}
pub struct MyDataMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for MyDataMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
actix_web::dev::forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
println!("In middleware");
let app_data = req.app_data::<actix_web::web::Data<Data>>();
// THIS NEXT LINE FAILS
// thread 'actix-rt|system:0|arbiter:0' panicked at 'called `Option::unwrap()` on a `None` value'
let state = app_data.as_ref().unwrap();
let color = state.as_ref().color.clone();
let fut = self.service.call(req);
println!("Color in middleware:{}", color);
Box::pin(async move {
let res = match fut.await {
Ok(response) => response,
Err(error) => panic!("Unable to process middleware:{}", error),
};
Ok(res)
})
}
}
// END MIDDLEWARE
// MAIN CODE
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let new_data = Data::new().await;
let data = actix_web::web::Data::new(new_data);
let server = match HttpServer::new(move || {
App::new()
.wrap(MyData)
.app_data(data.clone())
})
.bind("0.0.0.0:9000")
{
Ok(value) => value,
Err(error) => panic!("Error binding to socket:{:?}", error),
};
server.run().await
}
# Cargo.toml
[package]
name = "actix-middleware"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix = "0.13.0"
actix-web = "4.0.1"
futures = "0.3.21"
I feel like I'm pretty close. Any ideas would be greatly appreciated.