-
Rust: actix + MongoDB컴퓨터/Rust 2021. 8. 28. 09:59728x90반응형
actix
Actix + MongoDB
NoSQL 중 Document 개념을 사용하는 MongoDB
웹 프레임워크인 actix에 mongoDB를 사용하는 예제 (backend)
mongoDB는 atlas에서 무료로 간단한 서버를 만들었다.
Setup
Cargo.toml
De/Serialize 하기 위한 serde, futures는 try_next()란 cursor에서 iterate 하기 위해 필요함
[dependencies] mongodb = "2.0.0-beta.3" actix-rt = "2" actix-http = "2" actix-web = "4.0.0-beta.8" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_derive = "1.0" futures = "0.3"
src/lib.rs
type Mongo를 엔드포인트 함수에 web::Data <Mongo>처럼 사용하면 된다.
#![feature(proc_macro_hygiene, decl_macro)] #[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_json; extern crate mongodb; use mongodb::Client; use std::sync::Mutex; pub type Mongo = Mutex<Client>; mod db; mod routes; pub use db::model; pub use routes::*; // mongo+srv//id:password~~~~ pub const MONGO_URL: &str = env!("MONGODB_URL"); pub const SERVER: &str = "0.0.0.0:8010";
src/main.rs
몽고 DB는 Mutex에 client를 만들어서 actix의 app_data에 clone 하면 된다.
use actix_web::{middleware, web, App, HttpServer}; use mongodb::{options::ClientOptions, Client}; use std::sync::Mutex; #[actix_web::main] async fn main() -> std::io::Result<()> { // MongoDB Client let client_options = ClientOptions::parse(project::MONGO_URL).await.unwrap(); let client = web::Data::new(Mutex::new(Client::with_options(client_options).unwrap())); // start http server HttpServer::new(move || { App::new() .app_data(client.clone()) // store db pool in app state .wrap(middleware::Logger::default()) .service(project::hello::hello) }) .bind(project::SERVER)? .run() .await }
src/db/model.rs
테스트는 대학교 공지를 이용할 것이다.
MongoDB에 이미 아래 field처럼 공지 1650개를 저장해 두었다.
#[derive(Serialize, Deserialize, Debug, Default, Clone)] pub struct Notice { pub id: i32, pub category: String, pub title: String, pub date: String, pub link: String, pub writer: String, }
엔드포인트 예제
src/routes/hello.rs
이 예제는 GET /notice에 query를 같이 해서 보내면 필터링해서 공지를 json으로 return한다.
ex) GET ~/notice?date=21.01.06&category=학사 (21년 1월 6월에 "학사" 공지를 불러옴)
FindOptions에 limit, sort 같은 기능들이 있으니 @공식 문서 참고
#![allow(proc_macro_derive_resolution_fallback)] use crate::db::model::Notice; use crate::Mongo; use actix_web::{get, web, HttpRequest, HttpResponse, Responder}; use futures::stream::TryStreamExt; use mongodb::{bson::doc, options::FindOptions}; use std::collections::HashMap; #[get("/notice")] pub async fn hello(db: web::Data<Mongo>, req: HttpRequest) -> impl Responder { let params = web::Query::<HashMap<String, String>>::from_query(req.query_string()).unwrap(); // 아래와 같이 query를 보내면 Query struct엔 아래와 같이 Map으로 저장됨 // http://localhost:8010/notice?date=21.01.06&id=4 // Query({"id": "4", "date": "21.01.06"}) // println!("{:?}", params); let typed_collection = db .lock() .unwrap() .database("ajou") .collection::<Notice>("notice"); let date = params.get("date"); let cate = params.get("category"); // query 중 date, category 둘다 있는지 한 개만 있는지 체크해서 build let mut notices = if date.is_some() && cate.is_some() { typed_collection .find( doc! {"$and" : [{ "date": { "$eq": date } }, { "category": { "$eq": cate }}]}, None, ) // .find(doc! {"date": {"$eq": params.get("date")}}, None) .await .unwrap() } else if date.is_some() { typed_collection .find(doc! {"date": {"$eq": date}}, None) .await .unwrap() } else if cate.is_some() { typed_collection .find(doc! {"category": {"$eq": cate}}, None) .await .unwrap() } else { let find_options = FindOptions::builder().limit(1).build(); typed_collection.find(doc! {}, find_options).await.unwrap() }; let mut result: Vec<Notice> = Vec::new(); while let Some(notice) = notices.try_next().await.unwrap() { result.push(notice); } HttpResponse::Ok() .content_type("application/json") .json(json!(result)) } /* 결과 GET: http://localhost:8010/notice?date=21.08.26&category=학사 [ { "id": 13987, "category": "학사", "title": "[봉사활동] 2021 하반기 영통구청 저소득층 언택트 멘토링 자원봉사자 모집(~8/31)", "date": "21.08.26", "link": "https://www.ajou.ac.kr/kr/ajou/notice.do?mode=view&articleNo=112670&article.offset=0&articleLimit=1648", "writer": "사회봉사센터" }, { "id": 13988, "category": "학사", "title": "[다산학부대학] 2021학년도 2학기 신설 교과목 안내(기초수학A, 기초수학B)", "date": "21.08.26", "link": "https://www.ajou.ac.kr/kr/ajou/notice.do?mode=view&articleNo=112674&article.offset=0&articleLimit=1648", "writer": "다산학부대학교학팀" }, { "id": 13992, "category": "학사", "title": "(추가공지)[다산학부대학] 2021-2학기 Co-BSM 본수강신청 안내", "date": "21.08.26", "link": "https://www.ajou.ac.kr/kr/ajou/notice.do?mode=view&articleNo=112687&article.offset=0&articleLimit=1648", "writer": "다산학부대학교학팀" } ] */
728x90'컴퓨터 > Rust' 카테고리의 다른 글
Rust: Cross compile to linux on windows (0) 2021.08.30 Rust: reqwest GET/POST snippet (0) 2021.08.19 Rust: actix를 이용하여 카카오 챗봇 만들기 (1) 2021.08.02