First of all - this is a Rust-first project. Some of the challenges could have been easily resolved by including C, JS or other languages, but the goal is to enable comfortable development of full-stack cross-platform apps in a single language while depending only on the default rust tooling. Thanks to the rust's low-level capabilities one can customize/optimize pretty much any app's component and compile it for all kinds of platforms. The range of possibilities is so wide that only C and C++ can exceed it, but rust provides much better development and maintenance experience in most cases. So, rust is an excellent choice as a foundation for any kind of application.

Second but not less important - prest is a web-focused framework. It respects HATEOAS constraint of the REST and focused on HTML to build cross-platform UIs. There are plenty of ways to build UIs and interactions between system's components, but web standards are the most widely supported ones - they can work fine on decades-old hardware and will be supported in the comming decades as well. They are also well-known among the developers and can progressively enchance user experiences with near-native performance using WebAssembly and WebGPU, which are also well supported in the rust ecosystem.

Architectural inspiration came from this proof-of-concept - combination of a rust-based Service Worker compiled into wasm with HTMX library. This will likely sound pretty wild if you haven't worked with these technologies, but the underlying idea is simple - extend the regular REST architecture with a client-side worker that can respond to some of the requests. Thanks to the wasm-bindgen and rust compiler's wasm target support you can easily build rendering code for both server and the service worker. Thanks to HTMX you can easily build dynamic UIs without writing a single line of javascript. And thanks to progressive web capabilities this combo easily becomes a native-like installable application. These days PWAs can do quite a lot.

going native

In some cases you might need direct access to the client OS apis to enable some features that aren't supported in web environments (at least yet), so prest aims to support bindings to platforms' built-in webviews to enable distribution of the same restful apps as native packages using WRY and TAO. This way you can start building a usual web app and reuse it's code to build native client packages if needed. Unlike with React Native or Flutter you aren't locked in a specific framework's architecture but based in mature standards and provided with tools to expand capabilities as needed.

core dependencies

The core RESTful functionality is powered by axum's Router - simple and extremely flexible framework to compose routes and middleware. Prest adds a couple of utils to it to simplify common host needs: server startup with a bunch of common middleware, embedding files by lazily reading from disk in debug mode and including into the binary for the releases based on rust-embed, global state variables with Lazy initialization, integration for auth and a couple of others. But at the core it's still just re-exported router that supports all kinds of libraries from axum's ecosystem.

While axum has built-in helpers for the state management, they can introduce type-related issues if you're merging and nesting routers. So, I recommend using good old rust statics for state variables like DB connections and others, which also have a nice property of having the initializaiton logic right in the declaration. Also, prest includes a simple macro that allows using ? instead of unwraps and also runs async if necessary.

In some cases you might want to have lower-level control - for example to configure a proxy or to customize the runtime settings. In these cases you can easily import underlying crates directly and use only those prest utils which fit your needs. Under the hood its powered by tokio - general-purpose async runtime which provides exceptional performance for a wide range of applications, hyper for extremely reliable and efficient HTTP processing and tower-http for generic middleware.

templating utilities

Prest includes the html! macro, which is forked from maud to improve compatability with other prest's components, and also enchanced with built-in tailwind classes and htmx aliases. It allows to easily mix usual rust code with html templates and render them exceptionally fast. By default prest's Head utility imports tailwind's preflight styles and Script imports HTMX. Such combination provides everything necessary to develop UIs with styles and interactions right inside of the html and keep relevant bits of code close to each other. Also, if you want to bundle TypeScript, JavaScript, SASS or SCSS with your app prest provides a couple of build utilities that can run together with the rest of the app's build pipeline.

Another big thing common in FE development is state management. You can generally split every solution in 2 pieces: state storage and change signals. HATEOAS principle - Hypermedia As The Engine Of Application State suggests to use html itself as the current state of the app. You already have it and it's easy to observe, debug etc. Also, html has a built-in mechanism to signal that something happened - DOM events, and both htmx and hyperscript have exceptional tools to work with built-in ones and to create your own.

embedded database

Prest also packs with sled - embedded database (somewhat like RocksDB) written in rust from scratch. This crate and it's close relative Komora project are building next gen storage-layer solutions that utilize latest research in the field and focused on modern hardware. Reinventing a database might sound like a bit crazy idea, but:

According to it's discord server and discussions around the web there are already at least a couple of dozens of projects using sled. And I expect this number to grow dramatically once it will reach it's first stable release. But sled itself is only focused on being an efficient low-level storage layer that is expected to be used by higher-level libraries like

GlueSQL - SQL query parser and execution layer that can be attached to wide variety of storage options. It's even younger than sled, but can already be used from rust, python and javascript(both node and browser!). Also, it already supports sled, redis, in-memory, json, csv, and browser local, session and indexedDB storages. You can also define your own storage interfaces and even create composite ones that allow different storages for different tables while still supporting JOIN queries across them.

The main benefit of gluesql is that it allows to work with different storages on both client and server side using the same interface. As of now this interface has some issues and does not have anything like an ORM, but it ships with a query builder and you can use good old SQL. On top of that prest adds a Table derive macro that provides easy-to-use common CRUD operations.

This combo enables a zero-setup database in prest for your apps which can rely on in-memory storage, efficient disk persistance and even store data in the browser - all with the same sql-based interface.

authentication

User + session management is powered by axum-login which is quite fast and flexible. OAuth and OpenID flows are powered by openidconnect-rs which provides extensible strongly-typed interfaces. Even their basic examples are still pretty verbose, but prest integrates them together with the embedded database and other components so that you can just forward user requests to the relevant endpoints and the rest will be taken care of. Secure passwords handling is possible thanks to the password-auth crate.

others

While I've mentioned a whole bunch of libraries already, the list of dependencies that powers prest and makes it all possible is much longer so a huge thanks to everyone involved in their development:

Cargo.toml:47-109

...
[dependencies]
prest-html-macro = { path = "html/macro", version = "0.2.0", optional = true }
prest-embed-macro = { path = "embed/macro", version = "0.1.0", optional = true }
prest-embed-utils = { path = "embed/utils", version = "0.1.0", optional = true }
prest-db-macro = { path = "db/macro", version = "0.2.0", optional = true }
prest-serde-derive-fork = { path = "serde_derive_fork", version = "1.0.203" }

anyhow = "1.0.91"
thiserror = "1.0.63"
async-trait = "0.1.81"
itoa = "1"
mime_guess = "2"
tower = "0.4.13"
futures = "0.3"
tracing = "0.1.40"
serde = "1.0.203"
serde_json = "1"
chrono = "0.4"
time = { version = "0.3", features = ["wasm-bindgen"] } 
hex = { version = "0.4", optional = true }
axum-htmx = { version = "0.6", features = ["serde"] }
axum-valid = { version = "0.14", default-features = false, features = ["form", "json", "query", "422"] }
toml = "0.8.8"
semver = { version = "1.0", features = ["serde"] }
ansi-to-html = { version = "0.2.1", optional = true }

# host
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
axum = "0.7.9"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "net", "sync", "signal"] }
tower-http = { version = "0.5.1", features = ["catch-panic", "compression-br", "limit", "normalize-path"] }
dotenvy = "0.15"
tower-livereload = "0.9.3"
uuid = { version = "1.6", features = ["v4", "v7", "serde"] }
axum-server = { version = "0.7", features = ["tls-rustls"] }
gluesql = { git = "https://github.com/gluesql/gluesql.git", rev = "9e3f8fc", default-features = false, features = ["gluesql_sled_storage", "gluesql-shared-memory-storage"], optional = true }
tracing-subscriber = { version = "0.3.18", features = ["fmt", "chrono", "env-filter"], optional = true } 
tower-sessions = { version = "0.12", optional = true }
axum-login = { version = "0.15", optional = true }
openidconnect = { version = "3.5", optional = true }
password-auth = { version = "1", optional = true }
wry = { version = "0.35", optional = true }
tao = { version = "0.24", default-features = false, features = [ "rwh_05" ], optional = true }
tokio_schedule = "0.3.1"
directories = "5.0"
sled = "0.34"
russh = "0.44"
russh-keys = "0.44"
russh-sftp = "2.0.0-beta.2"
rustls-acme = { version = "0.11", features = ["axum"] }
rev_buf_reader = "0.3.0"
async-broadcast = "0.7.1"

# service worker
[target.'cfg(target_arch = "wasm32")'.dependencies]
axum = { version = "0.7.9", default-features = false, features = ["query", "form", "json", "matched-path", "original-uri"] }
wasm-bindgen = "0.2.93"
wasm-bindgen-futures = "0.4"
js-sys = "0.3.70"
console_error_panic_hook = "0.1.7"
web-sys = { version = "0.3.70", features = ["console", "FetchEvent",  "Request",  "ReadableStream",  "ReadableStreamDefaultReader", "Headers",  "ResponseInit",  "Response", "ServiceWorkerGlobalScope", "WorkerGlobalScope", "WorkerLocation"] }
uuid = { version = "1.6", features = ["v4", "v7", "serde", "js"] }
gluesql = { git = "https://github.com/gluesql/gluesql.git", rev = "9e3f8fc", default-features = false, features = ["gluesql-shared-memory-storage"], optional = true }
...

Besides them there are prest-build dependencies: SWC that powers typescript/js bundling, grass that powers SASS/SCSS processing, webmanifest that generates PWA manifests and toml which allows simple deserialization of configs.

v0.4.0
made by Egor Dezhic