Rocket: What is the best way to integrate the MongoDB in Rocket

Created on 18 Nov 2018  Â·  6Comments  Â·  Source: SergioBenitez/Rocket

I'm new to Rust, and Rocket.

Reading through the guide, There are support for MySQL, Postgres, Sqlite and Redis.

Then, What is the best way to integrate the MongoDB.
In addition, Is there any plan to add the official support for MongoDB and other NoSQL Database?

enhancement

Most helpful comment

Use r2d2 and r2d2-mongodb. I am using it works fine, but it is a little slow.

pub struct Conn(pub PooledConnection<MongodbConnectionManager>);

/*
    create a connection pool of mongodb connections to allow a lot of users to modify db at same time.
*/
pub fn init_pool() -> Pool<MongodbConnectionManager> {
    dotenv().ok();
    let mongo_addr = env::var("MONGO_ADDR").expect("MONGO_ADDR must be set");
    let mongo_port = env::var("MONGO_PORT").expect("MONGO_PORT must be set");
    let db_name = env::var("DB_NAME").expect("DB_NAME env var must be set");
    let manager = MongodbConnectionManager::new(
        ConnectionOptionsBuilder::new()
            .with_host(&mongo_addr)
            .with_port(mongo_port.parse::<u16>().unwrap())
            .with_db(&db_name)
            .build(),
    );
    match Pool::builder().max_size(64).build(manager) {
        Ok(pool) => pool,
        Err(e) => panic!("Error: failed to create mongodb pool {}", e),
    }
}

/*
    When Conn is dereferencd, return the mongo connection.
*/
impl Deref for Conn {
    type Target = <r2d2_mongodb::MongodbConnectionManager as ManageConnection>::Connection;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/*
    Create a implementation of FromRequest so Conn can be provided at every api endpoint
*/
impl<'a, 'r> FromRequest<'a, 'r> for Conn {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Conn, ()> {
        let pool = request.guard::<State<Pool<MongodbConnectionManager>>>()?;
        match pool.get() {
            Ok(db) => Outcome::Success(Conn(db)),
            Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())),
        }
    }
}


#[get("/hello")]
pub fn helloworld(
    conn: Conn,
) -> Json<Value> {
    let db = &conn;  // need to deref to get a mongo connection 
    db.collections("hello").insert_one(doc!{ "name": "John" }, None).unwrap();  
    Json(json!({ "status": "ok"}))
}


fn main() {

    // launch the app and mount all the api endpoints.
    rocket::ignite()
        .manage(init_pool())
        .mount("/", routes![helloworld)
        .launch();
}

All 6 comments

@SergioBenitez So, spiking a bit on this this morning and remembering why we didn't ship with MongoDB was because the r2d2 driver didn't accept a URI. Instead, it required we parse out the URI and feed it in separately. I'm more than happy to revisit adding support for it, though. I assume they're still compatible with one another (the Rust MongoDB driver has a couple recent updates).

I can continue working on this, if we'd like to make this a priority for rocket_contrib.

@ELD Yes, we should add support for mongodb; it's at least as popular as the other databases we support.

Aside from parsing the connection URL itself (user:pass@host:port/db into user, host, db, etc) we can submit a PR to the r2d2 crate and add support for this kind of URL. My feeling is that submitting a PR is the better approach; this seems like something that crate should support anyway. Should they refuse, we can implement the parsing here.

@SergioBenitez Sounds good. I can cook up a PR for r2d2-mongodb to handle the parsing. I agree that it should be handled there since the original adapter has a method to accept a connection from a URI.

Worst case, yes, we can implement the parsing within rocket_contrib, but having it upstream would be better.

Use r2d2 and r2d2-mongodb. I am using it works fine, but it is a little slow.

pub struct Conn(pub PooledConnection<MongodbConnectionManager>);

/*
    create a connection pool of mongodb connections to allow a lot of users to modify db at same time.
*/
pub fn init_pool() -> Pool<MongodbConnectionManager> {
    dotenv().ok();
    let mongo_addr = env::var("MONGO_ADDR").expect("MONGO_ADDR must be set");
    let mongo_port = env::var("MONGO_PORT").expect("MONGO_PORT must be set");
    let db_name = env::var("DB_NAME").expect("DB_NAME env var must be set");
    let manager = MongodbConnectionManager::new(
        ConnectionOptionsBuilder::new()
            .with_host(&mongo_addr)
            .with_port(mongo_port.parse::<u16>().unwrap())
            .with_db(&db_name)
            .build(),
    );
    match Pool::builder().max_size(64).build(manager) {
        Ok(pool) => pool,
        Err(e) => panic!("Error: failed to create mongodb pool {}", e),
    }
}

/*
    When Conn is dereferencd, return the mongo connection.
*/
impl Deref for Conn {
    type Target = <r2d2_mongodb::MongodbConnectionManager as ManageConnection>::Connection;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/*
    Create a implementation of FromRequest so Conn can be provided at every api endpoint
*/
impl<'a, 'r> FromRequest<'a, 'r> for Conn {
    type Error = ();

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Conn, ()> {
        let pool = request.guard::<State<Pool<MongodbConnectionManager>>>()?;
        match pool.get() {
            Ok(db) => Outcome::Success(Conn(db)),
            Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())),
        }
    }
}


#[get("/hello")]
pub fn helloworld(
    conn: Conn,
) -> Json<Value> {
    let db = &conn;  // need to deref to get a mongo connection 
    db.collections("hello").insert_one(doc!{ "name": "John" }, None).unwrap();  
    Json(json!({ "status": "ok"}))
}


fn main() {

    // launch the app and mount all the api endpoints.
    rocket::ignite()
        .manage(init_pool())
        .mount("/", routes![helloworld)
        .launch();
}

I think this has been resolved now that #838 is merged.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

loothood picture loothood  Â·  4Comments

kitsuneninetails picture kitsuneninetails  Â·  4Comments

klnusbaum picture klnusbaum  Â·  4Comments

shssoichiro picture shssoichiro  Â·  4Comments

lucklove picture lucklove  Â·  4Comments