warp icon indicating copy to clipboard operation
warp copied to clipboard

allow injecting a constant into a route

Open avnerbarr opened this issue 3 years ago • 4 comments

I have a object which needs to be used by all handlers. I'm not sure how to "share" this reference without recreating / singltoning it.

Toy example here:

struct Server {
  something_expensive: ExpensiveThing
}

impl Server  {
  fn do_something(&self) -> i32 { return 1}
}

fn main() {
   let server = Server::defaultI();
   // how do I pass this server into the "then" closure?
   warp::path("expensive").and(warp::body::json()).then(|request: Context| async move {
        let x = server.do_something(request); // this is an error:
        warp::reply::json(&x)
    });
}

---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `Fn`
    |                                                                   |
    |                                                                   the requirement to implement `Fn` derives from here

What I want:

2 options:

  1. use the struct function as a handler in "and" chain (but didn't work :( )
  2. pass the server into the closure as an "injected" argument i.e.
warp::path("expensive").and(warp::body::json()).then(|request: Context, server: Server <<<< This is passed along| async move {
server.do_something()
}

perhaps something like this exists but can't find it in documentation:

let server = Server::default();
warp::path("expensive").inject(server).and(warp::body::json()).then(|request: Context, server: Server| async move {

avnerbarr avatar Dec 22 '21 13:12 avnerbarr

Besides, maybe we can define a new filter named constant or similar that injects constants in the and chain:

pub fn constant<T: Clone + Send>(value: T) -> impl Filter<Extract = (T,)> + Copy;

warp::path!("path")
    .and(constant(server))
    .and(warp::body::json())
    .then(|server: Server, request: Context| { /* ... */ })

Lancern avatar Dec 24 '21 03:12 Lancern

Hi, have you seen the todos example and how the database is inserted?

jxs avatar Dec 28 '21 23:12 jxs

Hi , I didn't notice that example but in any case it gets cloned each time right?

fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = std::convert::Infallible> + Clone {
        warp::any().map(move || db.clone())
    }

avnerbarr avatar Dec 30 '21 12:12 avnerbarr

I didn't notice that example but in any case it gets cloned each time right?

It does, kind of. But the thing getting cloned is only an Arc<Something>, where Something can be your potentially expensive object. This way, the reference count will be increased and decreased for each matched route (so better put the thing after the actual url matching), but the object itself does not need to be cloned.

kaj avatar Mar 22 '22 15:03 kaj