ohkami - [狼] means wolf in Japanese - is simple and macro free web framework for Rust.
toml
[dependencies]
ohkami = "0.4"
```rust use ohkami::prelude::*;
fn main() -> Result<()> { Server::setup() .GET("/", || async { Response::OK("Hello, world!") }) .serve_on(":3000") } ```
Added experimental support for middlewares:
```rust fn main() -> Result<()> { let config = Config { logsubscribe: Some( tracingsubscriber::fmt() .withmaxlevel(tracing::Level::TRACE) ), ..Default::default() };
let middleware = Middleware::init()
.ANY("/*", || async {
tracing::info!("Hello, middleware!")
});
let thirdparty_middleware = some_crate::x;
Server::setup_with(config.and(middleware).and(x))
.GET("/", || async {
Response::OK("Hello!")
})
.serve_on("localhost:3000")
}
``
- "Middleware function" is just a function that takes one of nothing,
&Contextor
&mut Contextas its argument and returns
(). You can register such functions with their routes ( where they should work ) in a
Middleware.
- Middleware funcs is **inserted before** handler works, so middleware funcs are executed only when **the handler exists** ( e.g. In the code above for example,
tracing::info("Hello, middleware")!will NOT executed for a request
POST /` because no handler for this is found ).
- Current design may be changed in future version.
rust
let name = ctx.query::<&str>("name")?;
// `::<&str>` isn't needed when it's presumable
rust
let count = ctx.query::<usize>("count")?;
// `::<usize>` isn't needed when it's presumable
rust
let body = ctx.body::<D>()?;
// `::<D>` isn't needed when it's presumable
// `D` has to be `serde::Deserialize`
```rust fn main() -> Result<()> { Server::setup() .GET("/sleepy/:time/:name", sleepyhello) .serveon(":3000") }
async fn sleepyhello(time: u64, name: String) -> Result
text/plain
rust
Response::OK("Hello, world!")
application/json
rust
Response::OK(JSON("Hello, world!"))
rust
Response::OK(json!("ok": true))
rust
Response::OK(json(user)?)
// serialize Rust value into JSON
// value's type has to be `serde::Serialize`
```rust
let user = ctx.body::
// or, you can add an error context message:
let user = ctx.body::
// or discard original error:
let user = ctx.body::
rust
let handler = self.handler.as_ref()
._else(|| Response::NotFound("handler not found"))?;
// or
._else(|| Response::NotFound(None))?;
rust
(count < 10)
._else(|| Response::BadRequest("`count` must be less than 10"))?;
// or
._else(|| Response::BadRequest(None))?;
rust
fn main() -> Result<()> {
let config = Config {
log_subscribe: Some(
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
),
..Default::default()
};
Server::setup_with(config)
.GET("/", || async {Response::OK("Hello!")})
}
rust
let config = Config {
db_profile: DBprofile {
pool_options: PgPoolOptions::new().max_connections(20),
url: DB_URL.as_str(),
},
..Default::default()
};
rust
let user = sqlx::query_as::<_, User>(
"SELECT id, name FROM users WHERE id = $1"
).bind(1)
.fetch_one(ctx.pool())
.await?; // `Response` implements `From<sqlx::Error>`
```rust fn main() -> Result<()> { let middleware = Middleware::init() .ANY("/*", || async { tracing::info!("Hello, middleware!") });
Server::setup_with(middleware)
.GET("/", || async {
Response::OK("Hello!")
})
.serve_on("localhost:3000")
}
rust
fn main() -> Result<()> {
let config = Config {
logsubscribe: Some(
tracingsubscriber::fmt()
.withmaxlevel(tracing::Level::TRACE)
),
..Default::default()
};
let middleware = Middleware::init()
.ANY("/*", || async {
tracing::info!("Hello, middleware!")
});
let thirdparty_middleware = some_external_crate::x;
Server::setup_with(config.and(middleware).and(x))
.GET("/", || async {
Response::OK("Hello!")
})
.serve_on("localhost:3000")
} ```
main
function:
```rust
fn server() -> Server {
Server::setup()
.GET("/", || async {Response::OK("Hello!")})
}fn main() -> Result<()> {
server().serve_on(":3000")
}
2. import `test::Test` and others, and write tests using `assert_to_res` , `assert_not_to_res`:
rust
mod test { use ohkami::{server::Server, response::Response, test::{Test, Request, Method}}; use once_cell::sync::Lazy;
static SERVER: Lazy<Server> = Lazy::new(|| super::server());
#[test]
fn test_hello() {
let request = Request::new(Method::GET, "/");
(*SERVER).assert_to_res(&request, Response::OK("Hello!"));
(*SERVER).assert_not_to_res(&request, Response::BadRequest(None));
}
} ```
ohkami is on early stage now and not for producntion use. Please give me your feedback! → GetHub issue
This project is under MIT LICENSE (LICENSE-MIT or https://opensource.org/licenses/MIT).