41 releases (7 breaking)
new 0.7.8 | May 14, 2024 |
---|---|
0.6.0 | Apr 27, 2024 |
0.5.2 | Mar 20, 2024 |
0.4.5 | Dec 15, 2023 |
0.4.3 | Nov 28, 2023 |
#130 in HTTP server
946 downloads per month
Used in hypers_middleware
235KB
6K
SLoC
⚡️ Quick Start
Cargo.toml
## use hypers's full, openapi feature
[dependencies]
hypers = { version = "0.7", features = ["full","openapi"] }
tokio = { version = "=1.37.0", features = ["full"] }
serde = { version = "=1.0.201", features = ["derive"] }
Rust Code
use hypers::prelude::*;
use serde::{Deserialize, Serialize};
#[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(
name = "api1",
hook = [middleware::stat_time],
components(
schemas(HeaderParam,Data)
)
)]
impl Api1 {
#[get(
"/header",
tag = "Parse request header",
responses(
(status = 200, description = "header successfully", body = HeaderParam)
),
)]
pub fn header(input: HeaderParam) -> impl Responder {
(200, Json(input))
}
// Uri Path Params
#[delete(
"/{id}/{name}/{firstName}",
tag = "Parse request URL path params",
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 name = {:?}\n id = {:?}\n first_name = {:?}",
data.name, data.id, data.first_name
),
)
}
// Uri Query Params
#[get(
"query",
tag = "Parse request URL query params",
params(Data),
hook = [middleware::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 {
// Context-Type : application/x-www-form-urlencoded
#[patch(
"form",
tag = "Submmit x-www-form-urlencoded data",
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)))
}
// Context-Type : multipart/form-data Form Fields
#[post(
"multipart_form",
tag = "Submmit multipart/form-data Form Fields data",
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)))
}
// Context-Type : application/json
#[post(
"create",
tag = "Submmit application/json data",
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))
}
// Url Query Params
#[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;
// Middleware Function
#[hook]
pub async fn stat_time(req: Request, next: &mut 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)
}
#[hook]
pub async fn middleware_01(req: Request, next: &mut Next<'_>) -> Result {
if req.method() == "GET" {
return next.next(req).await;
}
return Err(Error::Response(
401,
hypers::serde_json::json!("Bad request"),
));
}
#[hook]
pub async fn middleware_02(req: 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!("Bad request"),
));
}
}
#[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); // Vist browser http://127.0.0.1:7878/swagger-ui/
println!("root router = {:#?}", root);
let listener = hypers::TcpListener::bind("127.0.0.1:7878").await?;
hypers::listen(root, listener).await
}
Dependencies
~14–30MB
~516K SLoC