I'm trying to setup a simple GET
filter, but I'm having trouble getting it to compile.
This is the function I'm trying to map to the request:
pub async fn get_users(reference_counter: Arc<RwLock<MysqlConnection>>) -> Result<impl Reply, Rejection> {
// Get users code here
}
This is how I map the function to the GET
request in main.rs
:
#[tokio::main]
async fn main() {
let db_connection = storage::establish_connection();
let lock = RwLock::new(db_connection);
let reference_counter = Arc::new(lock);
let ref_filter = warp::any().map(move || reference_counter.clone());
let get_users = warp::get()
.and(warp::path("users"))
.and(ref_filter.clone())
.and_then(user::get_users);
warp::serve(get_users).run(([127, 0, 0, 1], 3030)).await;
}
The compile error happens on and_then
, it's pretty cryptic and this what it says:
error[E0599]: no method named `and_then` found for struct `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>` in the current scope
--> src\main.rs:21:14
|
21 | .and_then(user::get_users);
| ^^^^^^^^ method not found in `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>`
|
::: C:\Users\Yasmani\.cargo\registry\src\github.com-1ecc6299db9ec823\warp-0.2.3\src\filter\and.rs:12:1
|
12 | pub struct And<T, U> {
| --------------------
| |
| doesn't satisfy `_: warp::filter::FilterBase`
| doesn't satisfy `_: warp::filter::Filter`
|
= note: the method `and_then` exists but the following trait bounds were not satisfied:
`warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
`&warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `&warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
`&mut warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::FilterBase`
which is required by `&mut warp::filter::and::And<warp::filter::and::And<impl warp::filter::Filter+std::marker::Copy, warp::filters::path::Exact<warp::filters::path::internal::Opaque<&str>>>, warp::filter::map::Map<impl warp::filter::Filter+std::marker::Copy, [closure@src\main.rs:17:39: 17:72 reference_counter:_]>>: warp::filter::Filter`
I believe it has something to do with the type being returned by the closure in ref_filter
not matching the type expected by the function get_users
, but I'm not sure why. I believe the closure returns an Arc<RwLock<MysqlConnection>>>
and the get_users
function takes the same. What is the problem?
The issue is that MysqlConnection
from the Diesel APIs does not implement some trait
that the Warp APIs require. The solution is to stop using the MysqlConnection
type directly here, and use a ConnectionPool
that generates connections on the fly instead. ConnectionPool
is part of the r2d2 feature of the Diesel package.
Now that I think about it, it makes perfect sense. Before, I was using a single database connection to process all incoming HTTP requests. This is bad, because the app could end up making multiple read operations on the same connection at the same time.
So, here is the function processing the HTTP request:
type ConnectionPool = Pool<ConnectionManager<MysqlConnection>>;
type ConnectionLock = RwLock<ConnectionPool>;
type ConnectionLockArc = Arc<ConnectionLock>;
pub async fn get_users(lock: ConnectionLockArc) -> Result<impl Reply, Rejection>{
let users = storage::get_users(&lock);
let response = json(&users);
return Ok(response);
}
And here is how it's setup with the Warp APIs:
#[tokio::main]
async fn main() {
let pool = storage::establish_connection_pool();
let lock = RwLock::new(pool);
let reference = Arc::new(lock);
let resources = warp::any().map(move || reference.clone());
let get_users = warp::get()
.and(warp::path("users"))
.and(resources.clone())
.and_then(user::get_users);
warp::serve(get_users).run(([127, 0, 0, 1], 3030)).await;
}