Search code examples
mongodbrustactix-web

Does the Rust Actix Web support MongoDB?


I have a new Backend Learning by Rust Programming. Starting from Web Framework. Since I would like to use Rust Backend with MongoDB so I have the example code of Nickel. Anyway, I also see that there is Actix Web Framework.

Does Actix Web support MongoDB like Nickel?

The following example provide the Nickel with MongoDB.

//main.rs — Nickel
#[macro_use] 
extern crate nickel;
extern crate rustc_serialize;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

// Nickel
use nickel::{Nickel, JsonBody, HttpRouter, MediaType};
use nickel::status::StatusCode::{self};

// MongoDB
use mongodb::{Bson, bson, doc};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::error::Result as MongoResult;

// bson
use bson::{Bson, Document};
use bson::oid::ObjectId;

// serde
use serde::{Serialize, Deserialize};

use std::fs::File;
use std::io::Read;
#[derive(Debug, Serialize, Deserialize)]
struct User {
    firstname: String,
    lastname: String,
    email: String
}

fn main(){
    let mut server = Nickel::new();
    let mut router = Nickel::router();

    router.get("/users", middleware! { |_req, _res|
        let client = Client::connect("localhost", 27017)
            .ok().expect("Error establishing connection.");

        let coll = client.db("rusty").collection("users");

        let mut cursor = coll.find(None, None).unwrap();
        let mut data_result = "{\"data\":[".to_owned();

        for (i, result) in cursor.enumerate() {

            if let Ok(item) = result {
                if let Some(&Bson::String(ref firstname)) = item.get("firstname") {
                    let string_data = if i == 0 {
                        format!("{},", firstname)
                    } else {
                        format!("{},", firstname)
                    };
                data_result.push_str(&string_data);
            }
        }
    }
    data_result.push_str("]}");

    format!("{}", data_result)

    });

    router.post("/users/new", middleware! { |_req, _res|
        let user = _req.json_as::<User>().unwrap();
        let firstname = user.firstname.to_string();
        let lastname = user.lastname.to_string();
        let email = user.email.to_string();

        let client = Client::connect("localhost", 27017)
            .ok().expect("Error establishing connection.");

        let coll = client.db("rusty").collection("users");

        match coll.insert_one(doc! {
            "firstname" => firstname,
            "lastname" => lastname,
            "email" => email
        }, None) {
            Ok(_) => (StatusCode::Ok, "Item saved!"),
            Err(e) => return _res.send(format!("{}", e))
        }
    });
    router.delete("/users/:id", middleware! { |_req, _res|
        let client = Client::connect("localhost", 27017)
            .ok().expect("Failed to initialize standalone client.");

        let coll = client.db("rusty").collection("users");

        let object_id = _req.param("id").unwrap();
        let id = match ObjectId::with_string(object_id) {
            Ok(oid) => oid,
            Err(e) => return _res.send(format!("{}", e))
        };
        match coll.delete_one(doc! {"_id" => id}, None) {
            Ok(_) => (StatusCode::Ok, "Item deleted!"),
            Err(e) => return _res.send(format!("{}", e))
        }
    });
    server.utilize(router);
    server.listen("0.0.0.0:3000").unwrap();
}

Solution

  • The short version is yes, it will, since your libraries return Results, and that's basically independent of whatever framework you decide to use.

    The long answer is yes, but with a word of caution. As the official mongoDB client (the one you are using) and pretty much every alternative out there have fully blocking operations (from the time you call find() to the time you get the Result, the main thread is blocked), this means that your entire event loop will potentially block during that interval.

    There seems to be no community effort to improve the underlying mongo C library, or to shift all the operations to another thread and provide data access to and from that thread, so you're short of options right now, sadly.