HTTP Request URL Parameters Syntax
| Pattern |
Kind |
Description |
:name |
Normal |
Matches a path piece, excludes / |
:name? |
Optional |
Matches an optional path piece, excludes / |
/:name?/ /:name? |
OptionalSegment |
Matches an optional path segment, excludes /, prefix or suffix should be / |
+ :name+ |
OneOrMore |
Matches a path piece, includes / |
* :name* |
ZeroOrMore |
Matches an optional path piece, includes / |
/*/ /* /:name*/ /:name* |
ZeroOrMoreSegment |
Matches zero or more path segments, prefix or suffix should be / |
⚡️ Quick Start
use hypers's full feature
use headers::{authorization::Bearer, Authorization};
use hypers::prelude::*;
use std::time::Instant;
use tracing::info;
#[derive(Serialize, Deserialize)]
pub struct CookieJarParams {
pub hypers: String,
pub rust: String,
}
#[derive(Serialize, Deserialize)]
pub struct HeaderParams {
pub host: Option<String>,
#[serde(rename(deserialize = "user-agent"))]
pub user_agent: Option<String>,
pub accept: Option<String>,
}
#[derive(Debug, Default, Serialize, Deserialize, Validate)]
pub struct UserController {
pub id: Option<u32>,
#[validate(email)]
pub email: Option<String>,
#[validate(range(min = 18, max = 20))]
pub age: Option<u16>,
}
#[controller(prefix = "api", version = 1, name = "user")]
impl UserController {
#[get("parse_cookies")]
pub async fn parse_cookies(req: Request) -> impl Responder {
let cookie_jar = req.parse_cookies::<CookieJarParams>()?;
Ok::<_, Error>((200, Json(cookie_jar)))
}
#[get("/parse_header")]
pub async fn parse_header(req: Request) -> impl Responder {
let header_params = req.parse_header::<HeaderParams>()?;
Ok::<_, Error>((200, Json(header_params)))
}
#[delete("parse_param/:id/:name/:age")]
pub async fn parse_param(req: Request, id: u32, name: String, age: u16) -> impl Responder {
let app_state = req.get::<Self>("user");
(
200,
format!(
"id = {}, name = {},age = {}\n app_state = {:#?}",
id, name, age, app_state
),
)
}
#[get("parse_param2/:id/:email/:age")]
pub async fn parse_param2(req: Request) -> impl Responder {
let user = req.parse_param::<UserController>()?;
user.validate()?; Ok::<_, Error>((200, Json(user)))
}
#[get("/parse_query")] pub async fn parse_query(query_params: Query<Self>) -> impl Responder {
Ok::<_, Error>((200, Json(query_params.0)))
}
#[get("/parse_form_get")]
#[patch("/parse_form_patch")]
#[validator(exclude("user"))] pub async fn parse_form_get(user: Form<UserController>) -> impl Responder {
(200, user)
}
#[post("/parse_json")] pub async fn parse_json(user: Json<UserController>) -> impl Responder {
(200, user)
}
#[post("/multipart_form")]
pub async fn multipart_form(mut req: Request) -> impl Responder {
let user = req.parse::<Self>().await?;
user.validate()?; Ok::<_, Error>((200, Json(user)))
}
#[post("/multipart_file")]
pub async fn multipart_file(mut req: Request) -> impl Responder {
let file = req.file("file").await?;
let file_name = file.name()?;
let file_name = file_name.to_string();
let img = req.files("imgs").await?;
let imgs_name = img
.iter()
.map(|m| m.name().unwrap().to_string())
.collect::<Vec<String>>()
.join(",");
Some((
200,
format!("file_name = {}, imgs_name = {}", file_name, imgs_name),
))
}
}
struct BasicController;
#[controller(name = "basic")]
impl BasicController {
#[get("/header")]
pub async fn header(req: Request) -> impl Responder {
let host = req.header::<String>("host")?;
let user_agent = req.header::<String>("user-agent")?;
Some((
200,
format!("host = {} , user_agent = {}", host, user_agent),
))
}
#[delete("/param/:name/:age")]
pub async fn param(req: Request) -> impl Responder {
let name = req.param::<String>("name")?;
let age = req.param::<u16>("age")?;
Some((200, format!("name = {} , age = {}", name, age)))
}
#[get("/query")]
pub async fn query(req: Request) -> impl Responder {
let name = req.query::<Vec<String>>("name")?;
let age = req.query::<u16>("age")?;
let key = req.get::<&str>("key")?;
Some((
200,
format!("name = {:?} , age = {}\n, app_state = {}", name, age, key),
))
}
#[get("/set_cookies")]
pub async fn set_cookies(_req: Request) -> impl Responder {
let mut cookie1 = Cookie::new("hypers", "hypers2023");
cookie1.set_path("/api/v1/user");
let mut cookie2 = Cookie::new("rust", "rust2023");
cookie2.set_path("/api/v1/user");
let mut cookie_jar = CookieJar::new();
cookie_jar.add(cookie1);
cookie_jar.add(cookie2);
(200, cookie_jar)
}
}
pub async fn websocket(req: Request, mut ws: WebSocket) -> Result<()> {
let name = req.param::<String>("name").unwrap_or_default();
while let Ok(msg) = ws.receive().await {
if let Some(msg) = msg {
match msg {
Message::Text(text) => {
let text = format!("{},{}", name, text);
ws.send(Message::Text(text)).await?;
}
Message::Close(_) => break,
_ => {}
}
}
}
Ok(())
}
pub async fn stat_time(req: Request, netx: Next) -> Result {
let start_time = Instant::now();
let res = netx.next(req).await?;
let elapsed_time = start_time.elapsed();
println!(
"The current request processing function takes time :{:?}",
elapsed_time
);
Ok(res)
}
pub async fn logger(req: Request, next: Next) -> Result {
let uri = req.uri().path();
info!("uri = {:?}", uri);
let res = next.next(req).await;
res
}
pub async fn app_state(mut req: Request, next: Next) -> Result {
let user = UserController {
id: Some(1),
email: Some("admin@gmail.com".to_owned()),
age: Some(21),
};
req.set("user", user);
req.set("key", "Hello World");
next.next(req).await
}
struct ApiKeyMiddleware {
api_key: String,
}
#[derive(Deserialize, Serialize)]
pub struct MiddlewareError<T> {
pub code: u32,
pub msg: String,
pub data: T,
}
#[middleware]
impl ApiKeyMiddleware {
async fn hook(&self, req: Request, next: Next) -> Result<Response> {
if let Some(bearer) = req.header_typed_get::<Authorization<Bearer>>() {
let token = bearer.0.token();
if token == self.api_key {
next.next(req).await
} else {
info!("Invalid token");
let res = MiddlewareError {
code: 400,
msg: String::from("Invalid token"),
data: "Invalid token",
};
Err(Error::Response(401, json!(res)))
}
} else {
info!("Not Authenticated");
Err(Error::Response(401, json!("Not Authenticated")))
}
}
}
fn main() -> Result<()> {
tracing_subscriber::fmt().compact().init();
let mut root = Router::new("/");
root.get("/*", StaticDir::new("hypers").listing(true))
.ws(":name/ws", websocket);
root.hook(logger, vec!["/basic"], None)
.hook(
app_state,
vec!["/api/v1/user/parse_param/:id/:name/:age", "/basic/query"],
None,
)
.hook(stat_time, vec!["/api/v1/user"], None)
.hook(
ApiKeyMiddleware {
api_key: "hypers".to_owned(),
},
vec!["/basic"],
vec!["/api/v1/user"],
);
root.controller(UserController::default());
root.controller(BasicController);
println!("root router = {:#?}", root);
let app = hypers::new(root);
app.run("127.0.0.1:7878")
}