21 releases (7 breaking)

new 0.7.0 Jun 8, 2024
0.6.1 Jun 8, 2024
0.5.2 Jun 4, 2024
0.4.0 May 31, 2024
0.0.10 May 24, 2024

#485 in Network programming

Download history 86/week @ 2024-03-14 19/week @ 2024-03-21 8/week @ 2024-03-28 1/week @ 2024-04-04 60/week @ 2024-05-09 416/week @ 2024-05-16 507/week @ 2024-05-23 884/week @ 2024-05-30

1,867 downloads per month

MIT license

62KB
879 lines

Qubit: Seamless RPC For Rust & TypeScript

crates.io docs.rs npm checks

Tired of wrestling with RPC boilerplate? Qubit simplifies communication between your Rust services and TypeScript clients, offering a type-safe and feature-rich development experience, so you can focus on building amazing applications.

Features:

  • Generated Type-Safe Clients: Say goodbye to manual type definitions, Qubit automatically generates TypeScript clients based on your Rust API, ensuring a smooth development experience.

  • Subscriptions: Build real-time, data-driven applications with subscriptions, allowing for your Rust server to push data directly to connected TypeScript clients.

  • Build Modular APIs: Organise your API handlers into nested routers, ensuring simplicity and maintainability as your service grows.

  • Serde Compatibility: Leverage Serde for seamless data serialisation and deserialisation between Rust and TypeScript.

  • Built on JSONRPC 2.0: Need a non-TypeScript client? Use any JSONRPC client in any language over WebSockets or HTTP.

  • Proven Base: Built on established libraries like ts-rs for type generation and jsonrpsee as the JSONRPC implementation.

Getting Started

  1. Add the required dependencies
# Cargo.toml
[dependencies]
qubit = "0.6.1"

ts-rs = "8.1.0" # Required to generate TS types
serde = { version = "1.0", features = ["derive"] } # Required for serialisable types
futures = "0.3.30" # Required for streaming functionality

tokio = { version = "1.35", features = ["full"] }
axum = "0.6"
hyper = { version = "0.14", features = ["server"] }
pnpm i @qubit-rs/client@latest
  1. Setup a Qubit router, and save the generated types
#[handler(query)]
async fn hello_world() -> String {
    "Hello, world!".to_string()
}

let router = Router::new()
    .handler(hello_world);

router.write_bindings_to_dir("./bindings");
  1. Attach the Qubit router to an Axum router, and start it
// Create a service and handle
let (qubit_service, _qubit_handle) = router.to_service(|_| async {}, |_| async {});

// Nest into an Axum router
let axum_router = axum::Router::<()>::new()
    .nest_service("/rpc", qubit_service);

// Start a Hyper server
axum::serve(
    tokio::net::TcpListener::bind(&SocketAddr::from(([127, 0, 0, 1], 9944)))
        .await
        .unwrap(),
    axum_router,
)
.await
.unwrap();
  1. Make requests from the TypeScript client
// Import transport from client, and generated server type
import { ws } from "@qubit-rs/client";
import type { QubitServer } from "./bindings";

// Connect with the API
const api = ws<QubitServer>("ws://localhost:9944/rpc");

// Call the handlers
const message = await api.hello_world.query();
console.log("received from server:", message);

Examples

Checkout all the examples in the examples directory.

FAQs

Qubit?

The term "Qubit" refers to the fundamental unit of quantum information. Just as a qubit can exist in a superposition of states, Qubit bridges the gap between Rust and TypeScript, empowering developers to create truly exceptional applications.

Prior Art

  • rspc: Similar concept, however uses a bespoke solution for generating TypeScript types from Rust structs, which isn't completely compatible with all of Serde's features for serialising and deserialising structs.

  • trpc: Needs no introduction, however it being restricted to TypeScript backends makes it relatively useless for Rust developers.

Dependencies

~11–25MB
~316K SLoC