Skip to content

Commit ba872ff

Browse files
committed
[+] Implement api with diesel (postgres)
1 parent 3eed1d7 commit ba872ff

File tree

6 files changed

+155
-55
lines changed

6 files changed

+155
-55
lines changed

api-practice/src/handlers.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.

api-practice/src/main.rs

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,38 @@
1-
use actix_web::{get, middleware, web, App, HttpResponse, HttpServer, Responder};
2-
mod handlers;
1+
#[macro_use]
2+
extern crate diesel;
33

4-
// #[get("/")]
5-
// async fn hello() -> impl Responder {
6-
// HttpResponse::Ok().body("Hello rust api!")
7-
// }
4+
use actix_web::{middleware, App, HttpServer};
5+
use diesel::prelude::*;
6+
use diesel::r2d2::{self, ConnectionManager};
7+
8+
mod schema;
9+
mod user;
10+
11+
pub type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;
812

913
#[actix_rt::main]
1014
async fn main() -> std::io::Result<()> {
15+
dotenv::dotenv().ok();
16+
1117
std::env::set_var("RUST_LOG", "actix_web=debug");
1218
env_logger::init();
1319

20+
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
21+
22+
// create db connection pool
23+
let manager = ConnectionManager::<PgConnection>::new(database_url);
24+
let pool: Pool = r2d2::Pool::builder()
25+
.build(manager)
26+
.expect("Failed to create pool.");
27+
1428
// Start http server
15-
HttpServer::new(|| {
29+
HttpServer::new(move || {
1630
App::new()
1731
.wrap(middleware::Logger::default())
18-
.route("/users", web::get().to(handlers::get_users))
19-
.route("/users/{id}", web::get().to(handlers::get_user_by_id))
20-
.route("/users", web::post().to(handlers::add_user))
21-
.route("/users/{id}", web::delete().to(handlers::delete_user))
32+
.data(pool.clone())
33+
.configure(user::route)
2234
})
2335
.bind("127.0.0.1:8080")?
2436
.run()
2537
.await
2638
}
27-
28-
// #[cfg(test)]
29-
// mod tests {
30-
// use super::*;
31-
// use actix_web::dev::Service;
32-
// use actix_web::{http, test, App, Error};
33-
34-
// #[actix_rt::test]
35-
// async fn test_hello() -> Result<(), Error> {
36-
// let app = App::new().service(hello);
37-
// let mut app = test::init_service(app).await;
38-
39-
// let req = test::TestRequest::get().uri("/").to_request();
40-
// let resp = app.call(req).await.unwrap();
41-
42-
// assert_eq!(resp.status(), http::StatusCode::OK);
43-
44-
// let response_body = match resp.response().body().as_ref() {
45-
// Some(actix_web::body::Body::Bytes(bytes)) => bytes,
46-
// _ => panic!("Response error"),
47-
// };
48-
49-
// assert_eq!(response_body, r##"Hello rust api!"##);
50-
51-
// Ok(())
52-
// }
53-
// }

api-practice/src/schema.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
table! {
2+
users (id) {
3+
id -> Int4,
4+
first_name -> Text,
5+
last_name -> Text,
6+
email -> Text,
7+
created_at -> Timestamp,
8+
}
9+
}

api-practice/src/user/handlers.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use crate::diesel::QueryDsl;
2+
use crate::diesel::RunQueryDsl;
3+
use crate::schema::users::dsl::*;
4+
use crate::user::models::{InputUser, NewUser, User};
5+
use crate::Pool;
6+
use actix_web::{web, Error, HttpResponse};
7+
use diesel::dsl::{delete, insert_into};
8+
use std::vec::Vec;
9+
10+
pub async fn get_users(db: web::Data<Pool>) -> Result<HttpResponse, Error> {
11+
Ok(web::block(move || get_all_users(db))
12+
.await
13+
.map(|user| HttpResponse::Ok().json(user))
14+
.map_err(|_| HttpResponse::InternalServerError())?)
15+
}
16+
17+
pub async fn get_user_by_id(
18+
db: web::Data<Pool>,
19+
user_id: web::Path<i32>,
20+
) -> Result<HttpResponse, Error> {
21+
Ok(
22+
web::block(move || db_get_user_by_id(db, user_id.into_inner()))
23+
.await
24+
.map(|user| HttpResponse::Ok().json(user))
25+
.map_err(|_| HttpResponse::InternalServerError())?,
26+
)
27+
}
28+
29+
pub async fn add_user(
30+
db: web::Data<Pool>,
31+
item: web::Json<InputUser>,
32+
) -> Result<HttpResponse, Error> {
33+
Ok(web::block(move || add_single_user(db, item))
34+
.await
35+
.map(|user| HttpResponse::Created().json(user))
36+
.map_err(|_| HttpResponse::InternalServerError())?)
37+
}
38+
39+
pub async fn delete_user(
40+
db: web::Data<Pool>,
41+
user_id: web::Path<i32>,
42+
) -> Result<HttpResponse, Error> {
43+
Ok(
44+
web::block(move || delete_single_user(db, user_id.into_inner()))
45+
.await
46+
.map(|user| HttpResponse::Ok().json(user))
47+
.map_err(|_| HttpResponse::InternalServerError())?,
48+
)
49+
}
50+
51+
fn get_all_users(pool: web::Data<Pool>) -> Result<Vec<User>, diesel::result::Error> {
52+
let conn = pool.get().unwrap();
53+
let items = users.load::<User>(&conn)?;
54+
Ok(items)
55+
}
56+
57+
fn db_get_user_by_id(pool: web::Data<Pool>, user_id: i32) -> Result<User, diesel::result::Error> {
58+
let conn = pool.get().unwrap();
59+
users.find(user_id).get_result::<User>(&conn)
60+
}
61+
62+
fn add_single_user(
63+
db: web::Data<Pool>,
64+
item: web::Json<InputUser>,
65+
) -> Result<User, diesel::result::Error> {
66+
let conn = db.get().unwrap();
67+
let new_user = NewUser {
68+
first_name: &item.first_name,
69+
last_name: &item.last_name,
70+
email: &item.email,
71+
created_at: chrono::Local::now().naive_local(),
72+
};
73+
let res = insert_into(users).values(&new_user).get_result(&conn)?;
74+
Ok(res)
75+
}
76+
77+
fn delete_single_user(db: web::Data<Pool>, user_id: i32) -> Result<usize, diesel::result::Error> {
78+
let conn = db.get().unwrap();
79+
let count = delete(users.find(user_id)).execute(&conn)?;
80+
Ok(count)
81+
}

api-practice/src/user/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
mod handlers;
2+
mod models;
3+
4+
use crate::user::handlers::{add_user, delete_user, get_user_by_id, get_users};
5+
use actix_web::web;
6+
7+
pub fn route(cfg: &mut web::ServiceConfig) {
8+
cfg.service(
9+
web::scope("/user")
10+
.service(web::resource("/get-all").route(web::get().to(get_users)))
11+
.service(web::resource("/get/{id}").route(web::get().to(get_user_by_id)))
12+
.service(web::resource("/add").route(web::post().to(add_user)))
13+
.service(web::resource("/del/{id}").route(web::delete().to(delete_user))),
14+
);
15+
}

api-practice/src/user/models.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::schema::*;
2+
use serde::{Deserialize, Serialize};
3+
4+
#[derive(Debug, Serialize, Deserialize)]
5+
pub struct InputUser {
6+
pub first_name: String,
7+
pub last_name: String,
8+
pub email: String,
9+
}
10+
11+
#[derive(Debug, Serialize, Deserialize, Queryable)]
12+
pub struct User {
13+
pub id: i32,
14+
pub first_name: String,
15+
pub last_name: String,
16+
pub email: String,
17+
pub created_at: chrono::NaiveDateTime,
18+
}
19+
20+
#[derive(Insertable, Debug)]
21+
#[table_name = "users"]
22+
pub struct NewUser<'a> {
23+
pub first_name: &'a str,
24+
pub last_name: &'a str,
25+
pub email: &'a str,
26+
pub created_at: chrono::NaiveDateTime,
27+
}

0 commit comments

Comments
 (0)