https://github.com/lunatic-solutions/submillisecond
A lunatic web framework
https://github.com/lunatic-solutions/submillisecond
Last synced: 7 days ago
JSON representation
A lunatic web framework
- Host: GitHub
- URL: https://github.com/lunatic-solutions/submillisecond
- Owner: lunatic-solutions
- License: mit
- Created: 2022-05-04T13:20:43.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-03-18T08:18:13.000Z (11 months ago)
- Last Synced: 2025-01-31T17:30:08.930Z (21 days ago)
- Language: Rust
- Size: 430 KB
- Stars: 911
- Watchers: 10
- Forks: 18
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 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/.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, 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