From c2a3a72e1e3d06de8aa303b07e1f40fb63bf640a Mon Sep 17 00:00:00 2001 From: Fankai Liu Date: Sun, 19 Nov 2023 22:39:56 +0800 Subject: [PATCH 1/4] add dependencie --- src/utils/create_project.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/create_project.rs b/src/utils/create_project.rs index 6437232..1295efd 100644 --- a/src/utils/create_project.rs +++ b/src/utils/create_project.rs @@ -694,6 +694,10 @@ fn handle_dependencies( conn_type: DbConnectionType, ) { if need_db_conn { + dependencies["validator"] = json!({ + "version": "0.16", + "features": ["derive"] + }); match (conn_type, db_type) { (DbConnectionType::Sqlx, DbType::Mysql) => { dependencies["sqlx"] = json!({ From 998ed5a366c69fae5f66117672e92aa9ef82ba73 Mon Sep 17 00:00:00 2001 From: Fankai Liu Date: Mon, 20 Nov 2023 22:36:26 +0800 Subject: [PATCH 2/4] add error type --- src/template/src/app_error.hbs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/template/src/app_error.hbs b/src/template/src/app_error.hbs index 6d73705..fe3f6bc 100644 --- a/src/template/src/app_error.hbs +++ b/src/template/src/app_error.hbs @@ -52,6 +52,10 @@ pub enum AppError { #[error("mongodb::bson::oid::Error`{0}`")] MongoBsonOidError(#[from] MongoBsonOidError), {{/if}} + {{#if need_db_conn}} + #[error("ValidationError:`{0}`")] + ValidationError(#[from] validator::ValidationErrors), + {{/if}} } pub type AppResult = Result; From edeaec7f24baac9d52fdebeedfec30289f9e2fd0 Mon Sep 17 00:00:00 2001 From: Fankai Liu Date: Thu, 23 Nov 2023 23:23:57 +0800 Subject: [PATCH 3/4] Improved Mongo DB templates --- src/template/src/app_error.hbs | 23 +------ src/template/src/app_response.hbs | 65 +++++++++++++++++++- src/template/src/dtos/user.hbs | 4 +- src/template/src/routers/demo.hbs | 2 +- src/template/src/routers/user.hbs | 96 +++++++++++++----------------- src/template/src/services/user.hbs | 20 ++++--- 6 files changed, 121 insertions(+), 89 deletions(-) diff --git a/src/template/src/app_error.hbs b/src/template/src/app_error.hbs index fe3f6bc..f1360f3 100644 --- a/src/template/src/app_error.hbs +++ b/src/template/src/app_error.hbs @@ -56,25 +56,4 @@ pub enum AppError { #[error("ValidationError:`{0}`")] ValidationError(#[from] validator::ValidationErrors), {{/if}} -} - -pub type AppResult = Result; - -#[async_trait] -impl Writer for AppError { - async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) { - {{#if is_web_site}} - res.stuff(StatusCode::INTERNAL_SERVER_ERROR, Json(self.to_string())); - {{else}} - res.render(Json(self.to_string())); - {{/if}} - } -} - -impl EndpointOutRegister for AppError { - fn register(_components: &mut salvo::oapi::Components, operation: &mut salvo::oapi::Operation) { - operation - .responses - .insert("500".to_string(), salvo::oapi::Response::new("error")); - } -} +} \ No newline at end of file diff --git a/src/template/src/app_response.hbs b/src/template/src/app_response.hbs index 8c72fa5..309f3f9 100644 --- a/src/template/src/app_response.hbs +++ b/src/template/src/app_response.hbs @@ -1,6 +1,48 @@ -use salvo::{prelude::StatusCode, writing::Json, Response}; +use salvo::{ + async_trait, + prelude::EndpointOutRegister, + writing::Json, + Depot, Request, Response, Writer, hyper::StatusCode, +}; use serde::Serialize; +use crate::app_error::AppError; + +pub struct AppResponse(pub AppResult); + +#[async_trait] +impl Writer for AppResponse { + async fn write(self, req: &mut Request, depot: &mut Depot, res: &mut Response) { + match self.0 { + Ok(data) => Res::with_data(data).into_response(res), + Err(e) => e.write(req, depot, res).await, + } + } +} + +impl EndpointOutRegister for AppResponse { + fn register(_components: &mut salvo::oapi::Components, operation: &mut salvo::oapi::Operation) { + operation + .responses + .insert("0".to_string(), salvo::oapi::Response::new("success")); + operation + .responses + .insert("500".to_string(), salvo::oapi::Response::new("error")); + } +} + +impl From> for AppResponse { + fn from(result: AppResult) -> Self { + AppResponse(result) + } +} + +impl From for AppResponse { + fn from(result: AppError) -> Self { + AppResponse(Err(result)) + } +} + #[derive(Debug, Serialize, Default)] pub struct Res { pub code: i32, @@ -17,7 +59,7 @@ pub struct ErrRes { impl Res { pub fn with_data(data: T) -> Self { Self { - code: 200, + code: 0, data, msg: "success".to_string(), } @@ -25,7 +67,7 @@ impl Res { #[allow(dead_code)] pub fn with_data_msg(data: T, msg: &str) -> Self { Self { - code: 200, + code: 0, data, msg: msg.to_string(), } @@ -51,3 +93,20 @@ impl ErrRes { res.stuff(StatusCode::INTERNAL_SERVER_ERROR, Json(self)); } } + +pub type AppResult = Result; + +#[async_trait] +impl Writer for AppError { + async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) { + ErrRes::with_err(&self.to_string()).into_response(res) + } +} + +impl EndpointOutRegister for AppError { + fn register(_components: &mut salvo::oapi::Components, operation: &mut salvo::oapi::Operation) { + operation + .responses + .insert("500".to_string(), salvo::oapi::Response::new("error")); + } +} diff --git a/src/template/src/dtos/user.hbs b/src/template/src/dtos/user.hbs index ddbcfd2..cbed8c7 100644 --- a/src/template/src/dtos/user.hbs +++ b/src/template/src/dtos/user.hbs @@ -1,8 +1,10 @@ use salvo::prelude::{ToSchema, Extractible}; use serde::{Deserialize, Serialize}; +use validator::Validate; -#[derive(Deserialize, Debug, ToSchema, Default)] +#[derive(Deserialize, Debug, Validate, ToSchema, Default)] pub struct UserAddRequest { + #[validate(length(min = 5, message = "username length must be greater than 5"))] pub username: String, pub password: String, } diff --git a/src/template/src/routers/demo.hbs b/src/template/src/routers/demo.hbs index dfdaf06..4cf774d 100644 --- a/src/template/src/routers/demo.hbs +++ b/src/template/src/routers/demo.hbs @@ -6,7 +6,7 @@ use salvo::{endpoint, writing::Text, Request, Response}; {{else}} use salvo::endpoint; {{/if}} -use crate::app_error::AppResult; +use crate::app_response::AppResult; {{#if is_web_site}} #[derive(Template)] diff --git a/src/template/src/routers/user.hbs b/src/template/src/routers/user.hbs index 5a54a7c..a9b6728 100644 --- a/src/template/src/routers/user.hbs +++ b/src/template/src/routers/user.hbs @@ -1,8 +1,9 @@ {{#if is_web_site}} use crate::{ - app_error::AppResult, - app_response::{ErrRes, Res}, - dtos::user::{UserAddRequest, UserLoginRequest, UserLoginResponse, UserUpdateRequest}, + app_response::{AppResponse, AppResult, ErrRes}, + dtos::user::{ + UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, + }, middleware::jwt::decode_token, services::user, }; @@ -19,7 +20,7 @@ use salvo::{ #[template(path = "login.html")] struct LoginTemplate {} -#[endpoint( tags("comm"),)] +#[endpoint(tags("comm"))] pub async fn login_page(res: &mut Response) -> AppResult<()> { let cookies = res.cookies(); let cookie = cookies.get("jwt_token"); @@ -35,7 +36,31 @@ pub async fn login_page(res: &mut Response) -> AppResult<()> { res.render(Text::Html(hello_tmpl.render().unwrap())); Ok(()) } -#[endpoint( tags("comm"),)] + +#[derive(Template)] +#[template(path = "user_list_page.html")] +pub struct UserListPageTemplate {} + +#[derive(Template)] +#[template(path = "user_list.html")] +pub struct UserListTemplate {} + +#[endpoint] +pub async fn user_list_page(req: &mut Request, res: &mut Response) -> AppResult<()> { + let is_fragment = req.headers().get("X-Fragment-Header"); + match is_fragment { + Some(_) => { + let hello_tmpl = UserListTemplate {}; + res.render(Text::Html(hello_tmpl.render().unwrap())); + } + None => { + let hello_tmpl = UserListPageTemplate {}; + res.render(Text::Html(hello_tmpl.render().unwrap())); + } + } + Ok(()) +} +#[endpoint(tags("comm"))] pub async fn post_login(req: JsonBody, res: &mut Response) { let result: AppResult = user::login(req.0).await; match result { @@ -51,69 +76,34 @@ pub async fn post_login(req: JsonBody, res: &mut Response) { } } -#[endpoint( tags("users"))] -pub async fn post_add_user(req: JsonBody, res: &mut Response) { - let result = user::add_user(req.0).await; - match result { - Ok(data) => Res::with_data(data).into_response(res), - Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), - } +#[endpoint(tags("users"))] +pub async fn post_add_user(new_user: JsonBody) -> AppResponse { + let result = user::add_user(new_user.0).await; + AppResponse(result) } #[endpoint( tags("users"), parameters( ("id", description = "user id"), ))] -pub async fn put_update_user(req: &mut Request, res: &mut Response) { - let req: UserUpdateRequest = req.extract().await.unwrap(); +pub async fn put_update_user(req: &mut Request) -> AppResult> { + let req: UserUpdateRequest = req.extract().await?; let result = user::update_user(req).await; - match result { - Ok(data) => Res::with_data(data).into_response(res), - Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), - } + Ok(AppResponse(result)) } -#[endpoint( tags("users"),)] -pub async fn delete_user(id: PathParam, res: &mut Response) { +#[endpoint(tags("users"))] +pub async fn delete_user(id: PathParam) -> AppResponse<()> { let result = user::delete_user(id.0).await; - match result { - Ok(_) => Res::with_data(()).into_response(res), - Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), - } + AppResponse(result) } -#[endpoint( tags("users"),)] -pub async fn get_users(res: &mut Response) { +#[endpoint(tags("users"))] +pub async fn get_users() -> AppResponse> { let result = user::users().await; - match result { - Ok(data) => Res::with_data(data).into_response(res), - Err(e) => ErrRes::with_err(&e.to_string()).into_response(res), - } + AppResponse(result) } -#[derive(Template)] -#[template(path = "user_list_page.html")] -pub struct UserListPageTemplate {} - -#[derive(Template)] -#[template(path = "user_list.html")] -pub struct UserListTemplate {} - -#[endpoint] -pub async fn user_list_page(req: &mut Request, res: &mut Response) -> AppResult<()> { - let is_fragment = req.headers().get("X-Fragment-Header"); - match is_fragment { - Some(_) => { - let hello_tmpl = UserListTemplate {}; - res.render(Text::Html(hello_tmpl.render().unwrap())); - } - None => { - let hello_tmpl = UserListPageTemplate {}; - res.render(Text::Html(hello_tmpl.render().unwrap())); - } - } - Ok(()) -} {{else}} use crate::{ app_error::AppResult, diff --git a/src/template/src/services/user.hbs b/src/template/src/services/user.hbs index e3a5b1e..a3a2cc1 100644 --- a/src/template/src/services/user.hbs +++ b/src/template/src/services/user.hbs @@ -436,14 +436,8 @@ pub async fn users() -> AppResult> { } {{/if}} {{#if is_mongodb}} -use std::str::FromStr; -use futures_util::StreamExt; -use mongodb::{ - bson::{doc, oid::ObjectId, Document}, - Collection, -}; use crate::{ - app_error::AppResult, + app_response::AppResult, db::{COLL_NAME, DB_NAME, MONGODB_CLIENT}, dtos::user::{ UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, @@ -451,11 +445,19 @@ use crate::{ middleware::jwt::get_token, utils::rand_utils, }; +use futures_util::StreamExt; +use mongodb::{ + bson::{doc, oid::ObjectId, Document}, + Collection, +}; +use std::str::FromStr; +use validator::Validate; pub async fn add_user(req: UserAddRequest) -> AppResult { + req.validate()?; let db = MONGODB_CLIENT .get() - .ok_or(anyhow::anyhow!("{{database_connection_failed}}"))?; + .ok_or(anyhow::anyhow!("数据库连接失败"))?; let coll_users = db.database(DB_NAME).collection::(COLL_NAME); let user = doc! { @@ -466,7 +468,7 @@ pub async fn add_user(req: UserAddRequest) -> AppResult { let user = coll_users .find_one(user, None) .await? - .ok_or(anyhow::anyhow!("{{user_does_not_exist}}"))?; + .ok_or(anyhow::anyhow!("用户不存在"))?; Ok(UserResponse { id: user.get_object_id("_id")?.to_string(), username: user.get_str("username")?.to_string(), From e4650a645724b5c1cb18ceeca715304e3461d441 Mon Sep 17 00:00:00 2001 From: Fankai Liu Date: Fri, 24 Nov 2023 20:38:13 +0800 Subject: [PATCH 4/4] better error handle --- src/template/src/app_error.hbs | 18 +----------------- src/template/src/routers/user.hbs | 2 +- src/template/src/services/user.hbs | 8 ++++---- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/template/src/app_error.hbs b/src/template/src/app_error.hbs index f1360f3..ee04f52 100644 --- a/src/template/src/app_error.hbs +++ b/src/template/src/app_error.hbs @@ -1,20 +1,4 @@ -{{#if is_web_site}} -use salvo::{ - async_trait, - http::ParseError, - prelude::{EndpointOutRegister, StatusCode}, - writing::Json, - Depot, Request, Response, Writer, -}; -{{else}} -use salvo::{ - async_trait, - http::ParseError, - prelude::EndpointOutRegister, - writing::Json, - Depot, Request, Response, Writer, -}; -{{/if}} +use salvo::http::ParseError; {{#if is_mongodb}} use mongodb::bson::document::ValueAccessError as MongoBsonAccessError; use mongodb::bson::oid::Error as MongoBsonOidError; diff --git a/src/template/src/routers/user.hbs b/src/template/src/routers/user.hbs index a9b6728..7312399 100644 --- a/src/template/src/routers/user.hbs +++ b/src/template/src/routers/user.hbs @@ -106,7 +106,7 @@ pub async fn get_users() -> AppResponse> { {{else}} use crate::{ - app_error::AppResult, + app_response::AppResult, app_response::{ErrRes, Res}, dtos::user::{UserAddRequest, UserLoginRequest, UserLoginResponse, UserUpdateRequest}, services::user, diff --git a/src/template/src/services/user.hbs b/src/template/src/services/user.hbs index a3a2cc1..57ae11f 100644 --- a/src/template/src/services/user.hbs +++ b/src/template/src/services/user.hbs @@ -1,7 +1,7 @@ {{#if is_sea_orm_or_sqlx}} {{#if is_sqlx}} use crate::{ - app_error::AppResult, + app_response::AppResult, db::DB, dtos::user::{ UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, @@ -14,7 +14,7 @@ use crate::{ {{/if}} {{#if is_sea_orm}} use crate::{ - app_error::AppResult, + app_response::AppResult, db::DB, dtos::user::{ UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, @@ -223,7 +223,7 @@ use uuid::Uuid; use crate::schema::users::dsl::users as diesel_users; use crate::{ - app_error::AppResult, + app_response::AppResult, db::establish_connection, dtos::user::{ UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, @@ -355,7 +355,7 @@ pub async fn users() -> AppResult> { use uuid::Uuid; use crate::{ - app_error::AppResult, + app_response::AppResult, dtos::user::{ UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest, },