examples
⚡️ Quick Start
Cargo.toml
[dependencies]
hypers = { version = "=0.6.0", features = ["full","openapi"] }
Rust Code
use hypers::prelude::*;
#[derive(Serialize, Deserialize, Extract, ToSchema)]
#[extract(header)] pub struct HeaderParam {
pub host: Option<String>,
#[serde(rename = "user-agent")]
pub user_agent: Option<String>,
pub accept: Option<String>,
}
#[derive(Serialize, Deserialize, IntoParams, ToSchema, Extract)]
#[into_params(parameter_in = Query)]
pub struct Data {
pub id: Option<u16>,
#[serde(rename = "firstName")]
pub first_name: Option<String>,
#[serde(rename = "lastName")]
pub last_name: Option<String>,
}
#[derive(Serialize, Deserialize, IntoParams, Extract)]
pub struct PathData {
pub name: Option<String>,
pub id: Option<u16>,
#[serde(rename = "firstName")]
pub first_name: Option<String>,
}
struct Api1;
#[openapi(
prefix = "", // 这个路由前缀可以省略不写
name = "api1",
hook = [middleware::stat_time], // 往 Api1 中注入 stat_time 这个中间件,则默认 Api1 下的所有路由将被这个中间件影响
components(
schemas(HeaderParam,Data)
)
)]
impl Api1 {
#[get(
"/header",
tag = "解析请求头",
responses(
(status = 200, description = "header successfully", body = HeaderParam)
),
)]
pub fn header(input: HeaderParam) -> impl Responder {
(200, Json(input))
}
#[delete(
"/{id}/{name}/{firstName}",
tag = "解析 URL 路径参数",
hook = [middleware::stat_time], // 因为 Api1 路由组中注册了 stat_time, 这里又再一次注册,因此当前这个 handler 将不被 stat_time 影响
params(PathData),
responses(
(status = 200, description = "param successfully", body = String)
)
)]
pub async fn param(data: PathData) -> impl Responder {
(
200,
format!(
"request url params:\n name = {:?}\n id = {:?}\n first_name = {:?}",
data.name, data.id, data.first_name
),
)
}
#[get(
"query",
tag = "解析 URL 查询参数",
params(Data),
hook = [middleware::middleware_01], // 因为 Api1 路由组中没有注册 middleware_01, 这里注册了,因此当前这个 handler 将被 middleware_01 影响
responses(
(status = 200, description = "query successfully", body = Data)
)
)]
pub async fn query(data: Data) -> impl Responder {
(200, Json(data))
}
}
struct Api2;
#[openapi(name = "api2", components(schemas(Data)))]
impl Api2 {
#[patch(
"form",
tag = "提交 x-www-form-urlencoded 格式的数据",
request_body(
content = Data,
content_type = "application/x-www-form-urlencoded",
),
responses(
(status = 200, description = "updated successfully", body = Data),
(status = 409, description = "Data already exists")
)
)]
pub async fn form(data: Data) -> impl Responder {
Ok::<_, Error>((200, Json(data)))
}
#[post(
"multipart_form",
tag = "提交 multipart/form-data Form Fields 格式的数据",
request_body(
content = Data,
content_type = "multipart/form-data",
),
responses(
(status = 200, description = "updated successfully", body = Data),
(status = 409, description = "Data already exists")
)
)]
pub async fn multipart_form(form_data: Data) -> impl Responder {
Ok::<_, Error>((200, Json(form_data)))
}
#[post(
"create",
tag = "提交 application/json 格式的数据",
request_body = Data,
responses(
(status = 200, description = "created successfully", body = Data),
(status = 409, description = "Data already exists")
)
)]
pub async fn create(data: Data) -> impl Responder {
Ok::<_, Error>((200, Json(data)))
}
}
struct Api3;
#[openapi(name = "api3", components(schemas(Data)))]
impl Api3 {
#[delete(
"/{id}/{name}",
tag = "parse request url path params",
params(
("id" = u16, Path, description = "Id of readme to delete"),
("name" = String, Path, description = "Name of readme to delete"),
),
responses(
(status = 200, description = "Parse Url Path Params successfully",body = Data),
(status = 400, description = "Parse Url Path Params failed")
))]
pub fn delete(id: Path<u16>,name: Path<String>) -> impl Responder {
(200,format!("id = {} name = {}",id.0,name.0))
}
#[get(
"/query_vec",
tag = "parse request url query params",
params(
("name" = Vec<String>, Query, description = "Url Query Params name"),
("age" = u16, Query, description = "Url Query Params age"),
),
responses(
(status = 200, description = "successfully", body = String),
(status = 400, description = "failed")
))]
pub fn query_vec(req: &mut Request) -> impl Responder {
let name = req.query::<Vec<String>>("name")?;
let age = req.query::<u16>("age")?;
Some((200, format!("name = {:?} , age = {}", name, age)))
}
}
mod middleware {
use super::*;
use std::time::Instant;
#[hook]
pub async fn stat_time(req: &mut Request, next: &mut Next<'_>) -> Result {
let start_time = Instant::now();
let res = next.next(req).await?;
let elapsed_time = start_time.elapsed();
println!(
"The current request processing function takes time :{:?}",
elapsed_time
);
Ok(res)
}
#[hook]
pub async fn middleware_01(req: &mut Request, next: &mut Next<'_>) -> Result {
if req.method() == "GET" {
return next.next(req).await;
}
return Err(Error::Response(
401,
hypers::serde_json::json!("错误的请求方法"),
));
}
#[hook]
pub async fn middleware_02(req: &mut Request, next: &mut Next<'_>) -> Result {
if req.uri().path().starts_with("/api1") {
return next.next(req).await;
}
return Err(Error::Response(
401,
hypers::serde_json::json!("错误的请求方法"),
));
}
}
#[tokio::main]
async fn main() -> Result<()> {
let mut root = Router::default();
root.push(Api1);
root.push(Api2);
root.push(Api3);
root.swagger("swagger-ui", None); println!("root router = {:#?}", root);
let listener = hypers::TcpListener::bind("127.0.0.1:7878").await?;
hypers::listen(root, listener).await
}