31 releases (5 breaking)
0.5.4 | Apr 7, 2024 |
---|---|
0.5.2 | Mar 20, 2024 |
0.4.5 | Dec 15, 2023 |
0.4.3 | Nov 28, 2023 |
#401 in HTTP server
357 downloads per month
Used in hypers_middleware
245KB
6.5K
SLoC
Router Dependent on matchit
OpenApi Dependent on utoipa
⚡️ Quick Start
Cargo.toml
## use hypers's full feature
[dependencies]
hypers = { version = "=0.5.4", features = ["full","openapi"] }
Rust Code
use hypers::prelude::*;
#[derive(Serialize, Deserialize, Extract, ToSchema)]
#[extract(source("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>,
pub name: Option<String>,
pub age: 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 email: Option<String>,
pub age: Option<u16>,
#[serde(rename = "firstName")]
pub first_name: Option<String>,
}
struct Api1;
#[openapi(
name = "api1",
hook = [middleware::stat_time],
components(
schemas(HeaderParam,Data)
)
)]
impl Api1 {
#[get(
path("/header"),
responses(
(status = 200, description = "header successfully", body = HeaderParam)
)
)]
pub fn header(input: HeaderParam) -> impl Responder {
(200, input)
}
// Uri Path Params
#[delete(
path("/{email}/{age}/{firstName}"),
hook = [middleware::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 email = {:?}\n age = {:?}\n name = {:?}",
data.email, data.age, data.first_name
),
)
}
// Uri Query Params
#[get(
path("query"),
params(Data),
responses(
(status = 200, description = "query successfully", body = Data)
)
)]
pub async fn query(data: Data) -> impl Responder {
(200, data)
}
}
struct Api2;
#[openapi(
name = "api2",
components(
schemas(Data)
)
)]
impl Api2 {
// Context-Type : application/x-www-form-urlencoded
#[patch(
path("form"),
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(user: Data) -> impl Responder {
Ok::<_, Error>((200, user))
}
// Context-Type : multipart/form-data Form Fields
#[post(
path("multipart_form"),
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, form_data))
}
// Context-Type : application/json
#[post(
path("create"),
request_body = Data,
responses(
(status = 200, description = "created successfully", body = Data),
(status = 409, description = "Data already exists")
)
)]
pub async fn create(user: Data) -> impl Responder {
Ok::<_, Error>((200, user))
}
}
struct Api3;
#[openapi(
name = "api3",
components(
schemas(Data)
)
)]
impl Api3 {
#[delete(
path("/{id}/{age}/{name}"),
tag = "parse request url path params",
params(
("id" = u16, Path, description = "Id of readme to delete"),
("age" = u16, Path, description = "Age 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")
))]
#[handler]
pub fn delete(id: Path<u16>, age: Path<u16>, name: Path<String>) -> impl Responder {
(
200,
Json(Data {
id: Some(id.0),
name: Some(name.0),
age: Some(age.0),
first_name: None,
last_name: None,
}),
)
}
// Url Query Params
#[get(
path("/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")
))]
#[handler]
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;
// Middleware Function
#[handler]
pub async fn stat_time(req: &mut Request, next: &Next<'_>) -> Result {
// Before executing the request processing function
let start_time = Instant::now();
// Calling subsequent request processing functions
let res = next.next(req).await?;
// After the execution of the request processing function
let elapsed_time = start_time.elapsed();
println!(
"The current request processing function takes time :{:?}",
elapsed_time
);
Ok(res)
}
}
fn main() -> Result<()> {
// Vist browser http://127.0.0.1:7878/swagger-ui/
let swagger = SwaggerUi::new("swagger-ui").urls(vec![
(Url::new("api1", "/api-docs/openapi1.json"), Api1.openapi()),
(Url::new("api2", "/api-docs/openapi2.json"), Api2.openapi()),
(Url::new("api3", "/api-docs/openapi3.json"), Api3.openapi()),
]);
let mut root: Router = swagger.into();
root.push(Api1.router());
root.push(Api2.router());
root.push(Api3.router());
println!("root router = {:#?}", root);
// Start Server
hypers::run(root, "127.0.0.1:7878")
}
Dependencies
~16–33MB
~558K SLoC