#Passing server_context data between axum middleware and server functions

1 messages · Page 1 of 1 (latest)

frank bobcat
#

I want to pass data between my axum middleware layers and my server functions (back and forth).

When "paying the price" of moving axum into the crate where the server functions are defined I can get at least the direction from middleware to server functions done by using extract on axum::Extension so there is some relationship between the two.

The docs of DioxusServerContext also state this: "A shared context for server functions that contains information about the request and middleware state.". Sadly it's totally unclear to me how to make this work for bidirectional communication between middleware and server functions.

Somewhat related: is there really no helper to initialize context providers and we have to the box monster?

mystic spire
#

And finally get it again in the middleware

#

You will need to wrap your context type in RwLock to make it mutable

frank bobcat
mystic spire
#

If the axum middleware is attached to the server function it should just work

#

A reproduction would be very helpful 🙂

frank bobcat
#

ah, you mean as in #[middleware]? currently my axum middleware just gets executed around my server functions ...

mystic spire
#

Yes, it would need to be in #[middleware]

#

Or you can wrap your custom middleware in the dioxus server context

frank bobcat
#

i'll try the latter first - this way i can't forget to add middleware someplace and run into issues with my sessiondata. how exactly would those two go together? the middleware and ProvideServerContext?

mystic spire
#

You would need to use ProvideServerContext to wrap the future in your middleware

#

It sets a global context whenever the future is run that makes the server context methods work

frank bobcat
#

couldn't get it to work really (minimal reproducible example will need to wait a bit). some observations:

i can build a server_context in a middleware like this:

    let parts = req.extract_parts().await.unwrap();
    let ctx = DioxusServerContext::new(parts);

However this won't contain the additional_context since that's populated out-of-band and is not available inside the extensions framework.

When wrapping the next future in ProvideServerContext I still could not get neither up- nor downstream directions to work. If the following is the entire axum middleware:

    let parts = req.extract_parts().await.unwrap();
    let ctx = DioxusServerContext::new(parts);

    let test: i32 = 42;

    ctx.insert(test);

    let next = ProvideServerContext::new(next.run(req), ctx);

    Ok(next.await)

Then I am still unable to extract test (as i32) in my server functions. The middleware layer is placed after serve_dioxus_application. The only way I can effectively send data upstream from my middleware currently uses axum extensions like this:

    req.extensions_mut().insert(session);

And then get it back using the server context in the function like that:

  let ctx = server_context();
  let mut rqp = ctx.request_parts_mut();
  let session = rqp.extensions.remove::<Session>();
GitHub

Fullstack app framework for web, desktop, mobile, and more. - DioxusLabs/dioxus

#

This would even be somewhat ok (not great because easily introduces server-side functionality into shared / neutral crates) if the direction back would work.

    let bar: u128 = 666;
    server_context().response_parts_mut().extensions.insert(bar);

Getting this back in the middleware does not work:

    let next = next.run(req).await;
    let foo = next.extensions().get::<u128>();

    // foo is None

    Ok(next)

I believe this is because extensions are not passed downstream but have not tried it, mostly because I could not easily get cargo patching for dioxus done.

GitHub

Fullstack app framework for web, desktop, mobile, and more. - DioxusLabs/dioxus

frank bobcat
#

one more thing regarding axum state in the equation: when we support axum state, extract and insert it into an extension in a middleware we can actually quite easily use axum state in server functions. would that kind of support for state management not be slightly more idiomatic / approachable then the server context?

frank bobcat
frank bobcat
#

i might just use the api wrong though

mystic spire
#

You need to wrap the whole middleware future in the context, not just the next middleware:

async fn session_middleware(mut req: Request, next: Next) -> Result<Response, StatusCode> {
    let parts = req.extract_parts().await.unwrap();
    let ctx = DioxusServerContext::new(parts);
    let future_context = ctx.clone();

    ProvideServerContext::new(
        async move {
            match extract::<FromContext<Session>, _>().await {
                Ok(session) => {
                    info!("CAN access session IN MIDDLEWARE: {:?}", session.0);
                }
                Err(e) => {
                    warn!("CANNOT access session IN MIDDLEWARE: {:?}", e);
                }
            }

            match extract::<FromContext<Session>, _>().await {
                Ok(session) => {
                    info!("CAN access session IN MIDDLEWARE: {:?}", session.0);
                }
                Err(e) => {
                    warn!("CANNOT access session IN MIDDLEWARE: {:?}", e);
                }
            }
            ctx.insert(State { foo: "bar2".into() });
            ctx.insert(Session { bar: "bar3".into() });

            let next = next.run(req).await;

            match extract::<FromContext<State>, _>().await {
                Ok(state) => {
                    info!(
                        "CAN read back state IN MIDDLEWARE from server function: {:?}",
                        state.0
                    );
                }
                Err(e) => {
                    warn!(
                        "CANNOT read back state IN MIDDLEWARE from server function: {:?}",
                        e
                    );
                }
            }

            Ok(next)
        },
        future_context,
    )
    .await
}
frank bobcat
#

i'll try that out right now, thanks a lot for the feedback that was really not obvious to me ...

frank bobcat
#

thanks again for the support but i am afraid i cannot get it to work. i do now the following at the end of my session middleware:

  let parts = req.extract_parts().await.unwrap(); // TODO: handle errors
  let ctx = DioxusServerContext::new(parts);
  let next_ctx = ctx.clone();

  ProvideServerContext::new(
      async move {
          if let Some(sess) = sess {
              debug!("adding session into context");
              ctx.insert(sess);
          }
           let next = (res_cookies, next.run(req).await).into_response();
           // TODO: extract cookie coming down via server context
           Ok(next)
      },
      next_ctx,
  )
  .await

and try to extract an (existing) session in a server function like that:

  let sess: Result<FromContext<Session>, _> = extract().await;
frank bobcat
#

if what i'm trying to do is somehow not supported, can we (as an alternative to it) call extend on the response extensions here?

mystic spire