submillisecond 0.4.1

A lunatic web framework for Rust.
Documentation
# submillisecond

A [lunatic] web framework for the Rust language.

Submillisecond is a **backend** web framework around the Rust language,
[WebAssembly's][wasm] security and the [lunatic scheduler][lunatic_gh].

> 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.

If you would like to ask for help or just follow the discussions around Lunatic & submillisecond,
[join our discord server][discord].

# Features

- Fast compilation times
- async-free - All preemption and scheduling is done by [lunatic][lunatic_gh]
- strong security - Each request is handled in a separate _lunatic_ process
- Batteries included
  - Cookies
  - Json
  - Logging
  - Websockets
- [Submillisecond LiveView] - Frontend web framework

[submillisecond liveview]: https://github.com/lunatic-solutions/submillisecond-live-view

# Code example

```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")
}
```

## Getting started with lunatic

To run the example you will first need to download the lunatic runtime by following the
installation steps in [this repository][lunatic_gh]. 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][lunatic_gh] applications need to be compiled to [WebAssembly][wasm] 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
# Add the WebAssembly target
rustup target add wasm32-wasi
# Build the app
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
```

#### Better developer experience

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`.

## Getting started with submillisecond

Add it as a dependency

```toml
submillisecond = "0.3.0"
```

## Handlers

Handlers are functions which return a response which implements [`IntoResponse`][intoresponse].

They can have any number of arguments, where each argument is an [extractor].

```rust
fn index(body: Vec<u8>, cookies: Cookies) -> String {
    // ...
}
```

## Routers

Submillisecond provides a [`router!`][router] macro for defining routes in your app.

```rust
#[derive(NamedParam)]
struct User {
    first_name: String,
    last_name: String,
}

fn hi(user: User) -> String {
    format!("Hi {} {}!", user.first_name, user.last_name)
}

fn main() -> std::io::Result<()> {
    Application::new(router! {
        GET "/hi/:first_name/:last_name" => hi
        POST "/update_data" => update_age
    })
    .serve("0.0.0.0:3000")
}
```

The router macro supports:

- [Nested routes]#nested-routes
- [Url parameters]#url-parameters
- [Catch-all]#catch-all
- [Guards]#guards
- [Middleware]#middleware

### Nested routes

Routes can be nested.

```rust
router! {
    "/foo" => {
        GET "/bar" => bar
    }
}
```

### Url parameters

Uri parameters can be captured with the [Path] extractor.

```rust
router! {
    GET "/users/:first/:last/:age" => greet
}

fn greet(Path((first, last, age)): Path<(String, String, u32)>) -> String {
    format!("Welcome {first} {last}. You are {age} years old.")
}
```

You can use the [NamedParam] derive macro to define named parameters.

```rust
router! {
    GET "/users/:first/:last/:age" => greet
}

#[derive(NamedParam)]
struct GreetInfo {
    first: String,
    last: String,
    age: u32,
}

fn greet(GreetInfo { first, last, age }: GreetInfo) -> String {
    format!("Welcome {first} {last}. You are {age} years old.")
}
```

Alternatively, you can access the params directly with the [Params] extractor.

### Catch-all

The `_` syntax can be used to catch-all routes.

```rust
router! {
    "/foo" => {
        GET "/bar" => bar
        _ => matches_foo_but_not_bar
    }
    _ => not_found
}
```

### Guards

Routes can be protected by guards.

```rust
struct ContentLengthLimit(u64);

impl Guard for ContentLengthLimit {
    fn check(&self, req: &RequestContext) -> bool {
        // ...
    }
}

router! {
    "/short_requests" if ContentLengthGuard(128) => {
        POST "/super" if ContentLengthGuard(64) => super_short
        POST "/" => short
    }
}
```

Guards can be chained with the `&&` and `||` syntax.

### Middleware

Middleware is any handler which calls [`next_handler`][next_handler] on the request context.
Like handlers, it can use extractors.

```rust
fn logger(req: RequestContext) -> Response {
    println!("Before");
    let result = req.next_handler();
    println!("After");
    result
}

fn main() -> std::io::Result<()> {
    Application::new(router! {
        with logger;

        GET "/" => hi
    })
    .serve("0.0.0.0:3000")
}
```

Middleware can be chained together, and placed within sub-routes.

```rust
router! {
    with [mid1, mid2];

    "/foo" => {
        with [foo_mid1, foo_mid2];
    }
}
```

They can also be specific to a single route.

```rust
router! {
    GET "/" with mid1 => home
}
```

## Testing

Lunatic provides a macro `#[lunatic::test]` to turn your tests into processes. Check out the
[`tests`][tests] folder for examples.

# License

Licensed under either of

- Apache License, Version 2.0, (http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (http://opensource.org/licenses/MIT)

at your option.

[lunatic]: https://lunatic.solutions
[lunatic_gh]: https://github.com/lunatic-solutions/lunatic
[wasm]: https://webassembly.org
[discord]: https://discord.gg/b7zDqpXpB4
[tests]: /tests
[router]: https://docs.rs/submillisecond/latest/submillisecond/macro.router.html
[intoresponse]: https://docs.rs/submillisecond/latest/submillisecond/response/trait.IntoResponse.html
[params]: https://docs.rs/submillisecond/latest/submillisecond/params/struct.Params.html
[path]: https://docs.rs/submillisecond/latest/submillisecond/extract/path/struct.Path.html
[namedparam]: https://docs.rs/submillisecond/latest/submillisecond/derive.NamedParam.html
[extractor]: https://docs.rs/submillisecond/latest/submillisecond/extract/trait.FromRequest.html
[next_handler]: https://docs.rs/submillisecond/latest/submillisecond/struct.RequestContext.html#method.next_handler