18 releases (4 breaking)
0.5.2 | Apr 26, 2024 |
---|---|
0.5.1 | Apr 26, 2024 |
0.4.6 | Apr 26, 2024 |
0.3.2 | Apr 20, 2024 |
0.1.1 | Apr 18, 2024 |
#815 in HTTP server
33KB
510 lines
Feature
An out-of-the-box web server framework that is encapsulated based on salvo and sea-orm.
Use DataBase (sea-orm)
-
Add
sea-orm
dependency in your Cargo.toml -
Enable one of the following features or multiple, depending on what kind of databases you need
- mysql
- sqlite
- postgres
- Run the following command, see sea-orm documentation
- sea-orm-cli generate entity -o src/model
- Import the generated model in your
main.rs
file
- mod model;
- which databases are used is configurable in
config.toml
Use Http3
Enable http3
feature and config the relevant certificates in config.toml
Example:
use webserver_rs::prelude::*;
use salvo::prelude::*;
use salvo::jwt_auth::HeaderFinder;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tokio::io::AsyncReadExt;
use webserver_rs::{
MemoryStream, authorization, build_cros, config::Config, expire_time, html_err,
json_err, router, FromConfigFile, HttpResult,
};
use webserver_rs::web_core::authorization::gen_token;
#[derive(Debug, Serialize, Deserialize)]
#[serde(crate = "serde")]
struct JwtClaim {
username: String,
exp: i64, // required
}
#[handler]
pub fn hello(req: &mut Request, res: &mut Response) -> HttpResult<()> {
let c = req.query::<String>("id");
println!("{c:?}");
let p = req.query::<String>("id").ok_or(html_err!(
400,
json!({
"status":"fail",
"msg":"id not found"
})
.to_string()
))?;
res.render(Text::Plain(format!("hello, {p}")));
Ok(())
}
#[handler]
pub fn login(depot: &mut Depot, res: &mut Response) -> HttpResult<()> {
let config = depot.obtain::<Config>().map_err(|_e| {
crate::json_err!(400,{
"status":"fail",
"msg":"config not found"
})
})?;
let token = gen_token(
config.secret_key.clone(),
JwtClaim {
exp: crate::expire_time!(Days(1)),
username: "a".to_string(),
},
)
.map_err(|e| crate::json_err!(400, {"err":e.to_string()}))?;
res.render(Text::Plain(token));
Ok(())
}
#[handler]
pub async fn image(res: &mut Response) -> HttpResult<()> {
let mut file = tokio::fs::File::open("./test.png")
.await
.map_err(|_| crate::html_err!(404, ""))?;
let mut s = Vec::new();
file.read_to_end(&mut s).await.unwrap();
res.stream(MemoryStream::new(s, 200));
Ok(())
}
#[handler]
pub async fn text_json(res: &mut Response) -> HttpResult<()> {
res.render(Text::Json(
json!({
"title":1
})
.to_string(),
));
Ok(())
}
mod ab {
use salvo::handler;
#[handler]
pub fn show() -> &'static str {
"abc"
}
pub mod shop {
#[super::handler]
pub fn show() -> &'static str {
"show"
}
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = Config::from_config_file("./config.toml").expect("config file not found");
let jwt = authorization::gen_jwt_auth::<JwtClaim>(
config.secret_key.clone(),
vec![Box::new(HeaderFinder::new())],
);
webserver_rs::serve_routes! {
config =>[
// http://localhost:8080/hello
router!([get, post] => @hello)
.hoop(jwt)
.hoop(authorization::AuthGuard::new(|_e| html_err!("unauthorized"))),
// http://localhost:8080/user/login
router!([get] => /user/@login),
// http://localhost:8080/a/b/show
router!([get, post] => a/b/@ab::show),
// http://localhost:8080/b/c/show/*
router!([get, post, put] => /b/c/@ab::show/<**path>),
// http://localhost:8080/test_json
router!([get, post] => @text_json).hoop(build_cros("*")),
// http://localhost:8080/ab/shop/show
router!([get, post] => ...@ab::shop::show).hoop(build_cros("*")),
] // (& [middlewares,])?
};
Ok(())
}
Dependencies
~34–58MB
~1M SLoC