A lunatic web framework for the Rust language.
Submillisecond is an attempt to build a backend web framework around the Rust language, WebAssembly's security and the lunatic scheduler.
This is an early stage project, probably has bugs and the API is still changing. It's also important to point out that many Rust crates don't compile to WebAssembly yet and can't be used with submillisecond.
```rust use submillisecond::{router, Application};
fn index() -> &'static str { "Hello :)" }
fn main() -> std::io::Result<()> { Application::new(router! { GET "/" => index }) .serve("0.0.0.0:3000") }
```
To run the example you will first need to download the lunatic runtime by following the
installation steps in this repository. The runtime is just a single executable and runs on
Windows, macOS and Linux. If you have already Rust installed, you can get it with:
bash
cargo install lunatic-runtime
Lunatic applications need to be compiled to WebAssembly before they can be executed by
the runtime. Rust has great support for WebAssembly and you can build a lunatic compatible
application just by passing the --target=wasm32-wasi
flag to cargo, e.g:
```bash
rustup target add wasm32-wasi
cargo build --release --target=wasm32-wasi ```
This will generate a .wasm file in the target/wasm32-wasi/release/
folder inside your project.
You can now run your application by passing the generated .wasm file to Lunatic, e.g:
lunatic target/wasm32-wasi/release/<name>.wasm
To simplify developing, testing and running lunatic applications with cargo, you can add a
.cargo/config.toml
file to your project with the following content:
```toml [build] target = "wasm32-wasi"
[target.wasm32-wasi] runner = "lunatic" ```
Now you can just use the commands you are already familiar with, such as cargo run
, cargo test
and cargo is going to automatically build your project as a WebAssembly module and run it inside
lunatic
.
Lunatic provides a macro #[lunatic::test]
to turn your tests into processes. Check out the
tests
folder for examples.
Add it as a dependency
toml
submillisecond = "0.2.0-alpha0"
Handlers are just functions that can define zero or more extractors.
rust
fn index(body: Vec<u8>, cookies: Cookies) -> String {
// ...
}
Handlers can return anything that implements IntoResponse
.
Submillisecond provides a router!
macro:
```rust
struct User { firstname: String, lastname: String, }
fn hi(user: User) -> String { format!("Hi {} {}!", user.firstname, user.lastname) }
fn main() -> std::io::Result<()> { Application::new(router! { GET "/hi/:firstname/:lastname" => hi POST "/updatedata" => updateage }) .serve("0.0.0.0:3000") } ```
GET parameters can be captured with an extractor.
Routes can be nested:
rust
router! {
"/foo" => {
GET "/bar" => bar
}
}
_
can be used as a catch-all helper:
rust
router! {
"/foo" => {
GET "/bar" => bar
_ => matches_foo_but_not_bar
}
_ => not_found
}
Sub/routes can be protected by a guard:
```rust struct ContentLengthLimit(u64);
impl Guard for ContentLengthLimit { fn check(&self, req: &RequestContext) -> bool { // ... } }
router! { "/shortrequests" if ContentLengthGuard(128) => { POST "/super" if ContentLengthGuard(64) => supershort POST "/" => short } } ```
Guards can be chained with the &&
and ||
syntax.
Middleware is just a function, like handlers it can use extractors.
```rust fn logger(req: RequestContext) -> Response { // before next handler let result = req.next_handler(); // after next handler result }
fn main() -> std::io::Result<()> { Application::new(router! { with logger;
GET "/hi/:first_name/:last_name" => hi
})
.serve("0.0.0.0:3000")
} ```
Middleware can be chained together or only be used in sub-routes:
```rust router! { with mid1; with mid2;
"/foo" => {
with foo_mid1;
with foo_mid2;
}
} ```
Licensed under either of
at your option.