51 releases (14 breaking)
0.15.0 | Feb 20, 2024 |
---|---|
0.13.0 | Feb 9, 2024 |
0.10.0 | Oct 28, 2023 |
0.9.2 | Jul 23, 2023 |
0.6.3 | Dec 30, 2022 |
#56 in HTTP server
348 downloads per month
340KB
7.5K
SLoC
ohkami
ohkami - [狼] wolf in Japanese - is intuitive and declarative web framework.- macro-less and type-safe APIs for intuitive and declarative code
- multi runtime support:
tokio
,async-std
Quick Start
- Add to
dependencies
:
# This sample uses `tokio` runtime.
# `async-std` is available by feature "rt_async-std".
[dependencies]
ohkami = { version = "0.15", features = ["rt_tokio"] }
tokio = { version = "1", features = ["full"] }
- Write your first code with ohkami : examples/quick_start
use ohkami::prelude::*;
use ohkami::typed::status::NoContent;
async fn health_check() -> NoContent {
NoContent
}
async fn hello(name: &str) -> String {
format!("Hello, {name}!")
}
#[tokio::main]
async fn main() {
Ohkami::new((
"/healthz"
.GET(health_check),
"/hello/:name"
.GET(hello),
)).howl("localhost:3000").await
}
- Run and check the behavior :
$ cargo run
$ curl http://localhost:3000/healthz
$ curl http://localhost:3000/hello/your_name
Hello, your_name!
Snippets
Handle path params
use ohkami::prelude::*;
#[tokio::main]
async fn main() {
Ohkami::new((
"/api/hello/:name"
.GET(hello),
)).howl("localhost:5000").await
}
async fn hello(name: &str) -> String {
format!("Hello, {name}!")
}
Handle request body / query params
use ohkami::prelude::*;
use ohkami::typed::status::Created;
use ohkami::typed::{Query, Payload, ResponseBody};
#[Payload(JSOND)] /* JSON + Deserialize */
struct CreateUserRequest<'req> {
name: &'req str,
password: &'req str,
}
#[ResponseBody(JSONS)] /* JSON + Serialize */
struct User {
name: String,
}
async fn create_user(body: CreateUserRequest<'_>) -> Created<User> {
Created(User {
name: String::from("ohkami")
})
}
#[Query] /* Params like `?lang=rust&q=framework` */
struct SearchQuery<'q> {
lang: &'q str,
q: &'q str,
}
#[ResponseBody(JSONS)]
struct SearchResult {
title: String,
}
async fn search(condition: SearchQuery<'_>) -> Vec<SearchResult> {
vec![
SearchResult { title: String::from("ohkami") },
]
}
#[Query]
, #[Payload( 〜 )]
derives FromRequest
trait impl for the struct.
( with path params : ({path params}, {FromRequest value}s...)
)
Use middlewares
ohkami's middlewares are called "fangs".
use ohkami::prelude::*;
struct LogRequest;
impl FrontFang for LogRequest { /* Called before a handler */
type Error = std::convert::Infallible;
async fn bite(&self, req: &mut Request) -> Result<(), Self::Error> {
println!("{req:?}");
Ok(())
}
}
struct SetServer;
impl BackFang for SetServer { /* Called after a handler */
type Error = std::convert::Infallible;
async fn bite(&self, res: &mut Response, _req: &Request) -> Result<(), Self::Error> {
res.headers.set()
.Server("ohkami");
Ok(())
}
}
#[tokio::main]
async fn main() {
Ohkami::with((LogRequest, SetServer), (
"/hello".GET(|| async {"Hello!"}),
)).howl("localhost:8080").await
/* Or, you can call them for any incoming requests
(regardless of request paths) :
{an Ohkami}
.howl_with(
(LogRequest, SetServer),
"localhost:8080"
).await
*/
}
Pack of Ohkamis
use ohkami::prelude::*;
use ohkami::typed::ResponseBody;
use ohkami::typed::status::{Created, NoContent};
#[ResponseBody(JSONS)]
struct User {
name: String
}
async fn create_user() -> Created<User> {
Created(User {
name: "ohkami web framework".to_string()
})
}
async fn health_check() -> NoContent {
NoContent
}
#[tokio::main]
async fn main() {
// ...
let users_ohkami = Ohkami::new((
"/".POST(create_user),
));
Ohkami::new((
"/healthz" .GET(health_check),
"/api/users".By(users_ohkami), // <-- nest by `By`
)).howl("localhost:5000").await
}
Testing
use ohkami::prelude::*;
use ohkami::testing::*; // <--
fn hello_ohkami() -> Ohkami {
Ohkami::new((
"/hello".GET(|| async {"Hello, world!"}),
))
}
#[cfg(test)]
#[tokio::test]
async fn test_my_ohkami() {
let ho = hello_ohkami();
let req = TestRequest::GET("/");
let res = ho.oneshot(req).await;
assert_eq!(res.status(), Status::NotFound);
let req = TestRequest::GET("/hello");
let res = ho.oneshot(req).await;
assert_eq!(res.status(), Status::OK);
assert_eq!(res.text(), Some("Hello, world!"));
}
Supported protocols
- HTTPS
- HTTP/1.1
- HTTP/2
- HTTP/3
- WebSocket
MSRV (Minimum Supported Rust Version)
Latest stable at the time of publication.
License
ohkami is licensed under MIT LICENSE (LICENSE or https://opensource.org/licenses/MIT).
Dependencies
~2–15MB
~184K SLoC