Coder Social home page Coder Social logo

ohkami-rs / ohkami Goto Github PK

View Code? Open in Web Editor NEW
36.0 4.0 4.0 2.13 MB

Ohkami - intuitive and declarative web framework for Rust

Home Page: https://crates.io/crates/ohkami

License: MIT License

Rust 100.00%
async rust web web-development declarative webframework async-std framework http tokio cloudflare cloudflare-workers server intuitive web-framework ohkami server-sent-events websocket graceful-shutdown

ohkami's Introduction

Ohkami

Ohkami - [狼] wolf in Japanese - is intuitive and declarative web framework.

  • macro-less and type-safe APIs for intuitive and declarative code
  • multiple runtimes are supported:tokio, async-std, worker (Cloudflare Workers)
License build check status of ohkami crates.io

Quick Start

  1. Add to dependencies :
[dependencies]
ohkami = { version = "0.20", features = ["rt_tokio"] }
tokio  = { version = "1",    features = ["full"] }
  1. Write your first code with Ohkami : examples/quick_start
use ohkami::prelude::*;
use ohkami::typed::status;

async fn health_check() -> status::NoContent {
    status::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
}
  1. Run and check the behavior :
$ cargo run
$ curl http://localhost:3000/healthz
$ curl http://localhost:3000/hello/your_name
Hello, your_name!

Feature flags

"rt_tokio", "rt_async-std"

Select a native async runtime

"rt_worker":Cloudflare Workers

npm create cloudflare ./path/to/project -- --template https://github.com/ohkami-rs/ohkami-templates/worker

Then your project directory has wrangler.toml, package.json and a Rust library crate. Local dev by npm run dev and deploy by npm run deploy !

See README of the template for details.

"graceful":Graceful Shutdown

Automatically catch Ctrl-C ( SIGINT ) and perform graceful shutdown.
Currently, only supported on rt_tokio.

"sse":Server-Sent Events

Ohkami responds with HTTP/1.1 Transfer-Encoding: chunked.
Use some reverse proxy to do with HTTP/2,3.

use ohkami::prelude::*;
use ohkami::typed::DataStream;
use ohkami::utils::stream;
use {tokio::time::sleep, std::time::Duration};

async fn sse() -> DataStream<String> {
    DataStream::from_stream(stream::queue(|mut q| async move {
        for i in 1..=5 {
            sleep(Duration::from_secs(1)).await;
            q.add(format!("Hi, I'm message #{i} !"))
        }
    }))
}

#[tokio::main]
async fn main() {
    Ohkami::new((
        "/sse".GET(sse),
    )).howl("localhost:5050").await
}

"ws":WebSocket

Ohkami only handles ws://.
Use some reverse proxy to do with wss://.

Currently, WebSocket on rt_worker is not supported.

use ohkami::prelude::*;
use ohkami::ws::{WebSocketContext, WebSocket, Message};

async fn echo_text(c: WebSocketContext<'_>) -> WebSocket {
    c.connect(|mut ws| async move {
        while let Ok(Some(Message::Text(text))) = ws.recv().await {
            ws.send(Message::Text(text)).await.expect("Failed to send text");
        }
    })
}

#[tokio::main]
async fn main() {
    Ohkami::new((
        "/ws".GET(echo_text),
    )).howl("localhost:3030").await
}

"nightly":enable nightly-only functionalities

  • try response
  • in-place schema validation

Snippets

Middlewares

Ohkami's request handling system is called "fangs", and middlewares are implemented on this.

builtin fang : CORS, JWT, BasicAuth, Timeout

use ohkami::prelude::*;

#[derive(Clone)]
struct GreetingFang;

/* utility trait; automatically impl `Fang` trait */
impl FangAction for GreetingFang {
    async fn fore<'a>(&'a self, req: &'a mut Request) -> Result<(), Response> {
        println!("Welcomm request!: {req:?}");
        Ok(())
    }
    async fn back<'a>(&'a self, res: &'a mut Response) {
        println!("Go, response!: {res:?}");
    }
}

#[tokio::main]
async fn main() {
    Ohkami::with(GreetingFang, (
        "/".GET(|| async {"Hello, fangs!"})
    )).howl("localhost:3000").await
}

Typed payload

builtin payload : JSON, Text, HTML, URLEncoded, Multipart

use ohkami::prelude::*;
use ohkami::typed::{status};
use ohkami::format::JSON;
/* `serde = 〜` is not needed in your [dependencies] */
use ohkami::serde::{Serialize, Deserialize};

/* Deserialize for request */
#[derive(Deserialize)]
struct CreateUserRequest<'req> {
    name:     &'req str,
    password: &'req str,
}

/* Serialize for response */
#[derive(Serialize)]
struct User {
    name: String,
}

async fn create_user(
    JSON(req): JSON<CreateUserRequest<'_>>
) -> status::Created<JSON<User>> {
    status::Created(JSON(
        User {
            name: String::from(req.name)
        }
    ))
}

Typed params

use ohkami::prelude::*;
use ohkami::format::{Query, JSON};
use ohkami::serde::{Serialize, Deserialize};

#[tokio::main]
async fn main() {
    Ohkami::new((
        "/hello/:name"
            .GET(hello),
        "/hello/:name/:n"
            .GET(hello_n),
        "/search"
            .GET(search),
    )).howl("localhost:5000").await
}

async fn hello(name: &str) -> String {
    format!("Hello, {name}!")
}

async fn hello_n((name, n): (&str, usize)) -> String {
    vec![format!("Hello, {name}!"); n].join(" ")
}

#[derive(Deserialize)]
struct SearchQuery<'q> {
    #[serde(rename = "q")]
    keyword: &'q str,
    lang:    &'q str,
}

#[derive(Serialize)]
struct SearchResult {
    title: String,
}

async fn search(
    Query(query): Query<SearchQuery<'_>>
) -> JSON<Vec<SearchResult>> {
    JSON(vec![
        SearchResult { title: String::from("ohkami") },
    ])
}

Static directory serving

use ohkami::prelude::*;

#[tokio::main]
async fn main() {
    Ohkami::new((
        "/".Dir("./dist"),
    )).howl("0.0.0.0:3030").await
}

File upload

use ohkami::prelude::*;
use ohkami::typed::status;
use ohkami::format::{Multipart, File};
use ohkami::serde::Deserialize;

#[derive(Deserialize)]
struct FormData<'req> {
    #[serde(rename = "account-name")]
    account_name: Option<&'req str>,
    pics: Vec<File<'req>>,
}

async fn post_submit(
    Multipart(data): Multipart<FormData<'_>>
) -> status::NoContent {
    println!("\n\
        ===== submit =====\n\
        [account name] {:?}\n\
        [  pictures  ] {} files (mime: [{}])\n\
        ==================",
        data.account_name,
        data.pics.len(),
        data.pics.iter().map(|f| f.mimetype).collect::<Vec<_>>().join(", "),
    );

    status::NoContent
}

Pack of Ohkamis

use ohkami::prelude::*;
use ohkami::typed::status;
use ohkami::format::JSON;
use ohkami::serde::Serialize;

#[derive(Serialize)]
struct User {
    name: String
}

async fn list_users() -> JSON<Vec<User>> {
    JSON(vec![
        User { name: String::from("actix") },
        User { name: String::from("axum") },
        User { name: String::from("ohkami") },
    ])
}

async fn create_user() -> status::Created<JSON<User>> {
    status::Created(JSON(User {
        name: String::from("ohkami web framework")
    }))
}

async fn health_check() -> status::NoContent {
    status::NoContent
}

#[tokio::main]
async fn main() {
    // ...

    let users_ohkami = Ohkami::new((
        "/"
            .GET(list_users)
            .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 t = hello_ohkami().test();

    let req = TestRequest::GET("/");
    let res = t.oneshot(req).await;
    assert_eq!(res.status(), Status::NotFound);

    let req = TestRequest::GET("/hello");
    let res = t.oneshot(req).await;
    assert_eq!(res.status(), Status::OK);
    assert_eq!(res.text(), Some("Hello, world!"));
}

Supported protocols

  • HTTP/1.1
  • HTTP/2
  • HTTP/3
  • HTTPS
  • Server-Sent Events
  • WebSocket

Benchmark Results

MSRV ( Minimum Supported Rust Version )

Latest stable

License

ohkami is licensed under MIT LICENSE ( LICENSE or https://opensource.org/licenses/MIT ).

ohkami's People

Contributors

kana-rus avatar mcpower avatar mizar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ohkami's Issues

I look forward to leveraging my extensive experience and knowledge to contribute to your team’s goals and achievements.

Hello, I'm Ethan Tan, a web full-stack and blockchain developer with more than 8 years in the field. I focus on building reliable, scalable web applications and advanced blockchain solutions. Leveraging my knowledge of React.js, Vue.js, and Next.js, combined with my Solidity skills for smart contract development, I provide high-quality, secure, and efficient solutions tailored to your distinct needs.

TODO

  • WebSocket
  • Server-Sent Events
  • static file serving
  • OpenAPI tool
  • reliable benchmark
  • Cloudflare Workers
  • graceful shutdown
  • HTTPS
  • HTTP2
  • HTTP3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.