# Turbocharger
[](https://github.com/trevyn/turbocharger)
[](https://crates.io/crates/turbocharger)
[](https://docs.rs/turbocharger)
Autogenerated async RPC bindings that instantly connect a JS or Rust/WASM frontend to a Rust backend via a WebSocket connection.
See [https://github.com/trevyn/turbocharger-template-dioxus](https://github.com/trevyn/turbocharger-template-dioxus) or [https://github.com/trevyn/turbocharger-template-svelte](https://github.com/trevyn/turbocharger-template-svelte) for a full turnkey template repository.
Makes a Rust _backend_ function, e.g.:
```rust,ignore
use turbocharger::prelude::*;
#[backend]
pub async fn get_person(id: i64) -> Person {
// ... write any async backend code here; ...
// ... query a remote database, API, etc. ...
Person { name: "Bob", age: 21 }
}
```
instantly available, with _no additional boilerplate_, to a frontend as
- an async Rust/WASM function
- AND optionally an async JavaScript function with full TypeScript type definitions
- that calls the backend over the network:
Rust/WASM:
```rust,ignore
let person = get_person(1).await;
```
JS:
```js
// export function get_person(id: number): Promise;
let person = await backend.get_person(1);
```
A Rust frontend works with any types that are serializable with `bincode`.
A JS frontend works with any types that are [supported by](https://rustwasm.github.io/docs/wasm-bindgen/reference/types.html) `wasm-bindgen`, which includes most basic types and custom `struct`s with fields of supported types, but [not yet](https://github.com/rustwasm/wasm-bindgen/pull/2631) `enum` variants with values (which would come out the other end as TypeScript discriminated unions).
## How It Works
A proc macro auto-generates a frontend `wasm-bindgen` module, which serializes the frontend's function call parameters with `bincode`. These requests are sent over a shared WebSocket connection to a provided `axum` endpoint on the backend server, which calls your backend function and serializes the response. This is sent back over the WebSocket and resolves the Promise or Future returned by the original frontend function call.
Multiple async requests can be simultaneously in-flight over a single multiplexed connection; it all just works.
## Complete Example: A full SQLite-powered backend with frontend bindings
See [https://github.com/trevyn/turbocharger-template-dioxus](https://github.com/trevyn/turbocharger-template-dioxus) or [https://github.com/trevyn/turbocharger-template-svelte](https://github.com/trevyn/turbocharger-template-svelte) for a full turnkey template repository.
### `app.rs`
```rust
use turbocharger::prelude::*;
use turbosql::Turbosql;
#[backend]
#[derive(Turbosql, Default)]
pub struct Person {
pub rowid: Option,
pub name: Option,
}
#[backend(js)]
pub async fn insert_person(p: Person) -> Result {
Ok(p.insert()?) // returns rowid
}
#[backend(js)]
pub async fn get_person(rowid: i64) -> Result {
Ok(turbosql::select!(Person "WHERE rowid = ?", rowid)?)
}
```
### `server.rs`
```rust,no_run
mod app;
#[tokio::main]
async fn main() {
#[derive(rust_embed::RustEmbed)]
#[folder = "build"]
struct Frontend;
eprintln!("Serving on http://127.0.0.1:8080");
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], 8080));
turbocharger::serve::(&addr).await;
}
```
### `wasm.rs`
```rust,no_run
mod app;
```
### `index.js`
```js
import turbocharger_init, * as backend from "./turbocharger_generated";
(async () => {
await turbocharger_init();
let person = Object.assign(new backend.Person(), { name: "Bob" });
let rowid = await backend.insert_person(person);
console.log((await backend.get_person(rowid)).toJSON());
})();
```
## Usage
Start a new project using [https://github.com/trevyn/turbocharger-template-dioxus](https://github.com/trevyn/turbocharger-template-dioxus) or [https://github.com/trevyn/turbocharger-template-svelte](https://github.com/trevyn/turbocharger-template-svelte) for the full project layout and build scripts.
Your `app.rs` module is included in both the server `bin` target in `server.rs` and a WASM target in `wasm.rs`. The `#[backend]` macro outputs three functions:
- Your function, unchanged, for the server `bin` target; you can call it directly from other server code if you wish.
- An internal function for the server `bin` target providing the RPC dispatch glue.
- A function for the WASM target that makes the RPC call and delivers the response.
Note that `app.rs` is compiled to both `wasm32-unknown-unknown` and the host triple, and that you can annotate functions and structs in `app.rs` with `#[backend]` or `#[frontend]`.
## Error Handling
`#[backend(js)]` functions that need to return an error can return a `Result` where `T` is a `wasm-bindgen`-compatible type and `E` is a type that implements `Display`, including any type implementing `std::error::Error`, including `Box>` and `anyhow::Error`. Errors crossing the network boundary are converted to a `String` representation on the server via their `to_string()` method and delivered as a Promise rejection on the JS side.
Returning `Result` is recommended, and will produce an error that includes the line number of the error location.
### License: MIT OR Apache-2.0 OR CC0-1.0 (public domain)