Difference Between iii Python, TypeScript, and Rust SDKs: A Complete Guide
The iii platform provides three officially supported SDKs—Python, TypeScript, and Rust—that expose identical core functionality but differ in type systems, error handling, and async runtime patterns.
The iii engine from the iii-hq/iii repository offers native SDKs for Python, TypeScript/JavaScript (Node and browser), and Rust. While all three SDKs communicate using the same WebSocket protocol defined in engine/src/protocol.rs, each implementation is idiomatic to its host language. This guide breaks down the architectural distinctions, source file locations, and practical usage patterns to help you choose the right SDK for your stack.
SDK Architecture and Language Paradigms
Each SDK wraps the engine's WebSocket protocol with language-specific ergonomics. The entry points and concurrency models reflect the distinct runtime characteristics of Python, TypeScript, and Rust.
Python SDK
The Python SDK (iii-sdk on PyPI) targets CPython 3.10+ and relies on asyncio for concurrency. All network operations are coroutines that must be awaited, and payloads are handled as dynamic Python dictionaries converted to JSON at runtime. Error handling follows the Python convention of raising exceptions.
Key source files:
- Core API:
sdk/packages/python/iii/src/iii/iii.py - Registration helpers:
register_functionandregister_triggerfunctions iniii.py - Observability:
sdk/packages/python/iii/src/iii/log.py
Error model: Raises iii.errors.IIIError (subclass of Exception).
TypeScript SDK
The TypeScript SDK (iii-sdk on npm) supports Node 18+ and browsers via the iii-browser-sdk package. It uses standard JavaScript Promise objects with async/await syntax and provides strong compile-time typing through interfaces like IIIRegisterFunction and IIITriggerConfig. The SDK includes WebSocket auto-reconnect utilities for browser environments.
Key source files:
- Core API:
sdk/packages/node/iii/src/iii.ts - Registration: Re-exported via
index.tswithregisterFunctionandregisterTrigger - Logging:
sdk/packages/node/iii/src/logger.ts
Error model: Returns Promise<T> that rejects on failure.
Rust SDK
The Rust SDK (iii-sdk on crates.io) requires Rust 1.70+ and offers zero-cost abstractions with no runtime reflection. It uses strongly-typed builder structs like RegisterFunction for configuration and returns Result<T, IIIError> for error propagation. Optional feature flags (such as observability and async-std) control extra functionality.
Key source files:
- Public API:
sdk/packages/rust/iii/src/lib.rs - Registration builders:
src/register.rs(e.g.,RegisterFunction,RegisterTrigger) - Logger:
src/logger.rs
Error model: Explicit Result<T, IIIError> returns with ? operator propagation.
Side-by-Side Implementation Comparison
The following examples demonstrate registering an HTTP trigger that accepts a POST request at /hello and returns a greeting. Each snippet assumes the iii engine is running locally at ws://localhost:8080.
Python Implementation
Install with: pip install iii-sdk
# file: hello.py
import asyncio
import iii
async def greet(payload: dict) -> dict:
name = payload.get("name", "world")
await iii.log_info(f"Greeting {name}")
return {"message": f"Hello, {name}!"}
async def main() -> None:
await iii.register_function(
function_id="hello::greet",
handler=greet,
description="Return a greeting",
)
await iii.register_trigger(
type="http",
function_id="hello::greet",
config={"api_path": "/hello", "http_method": "POST"},
)
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(main())
Source reference: The register_function and register_trigger coroutines are implemented in sdk/packages/python/iii/src/iii/iii.py.
TypeScript Implementation
Install with: pnpm install iii-sdk (or iii-browser-sdk for browser contexts)
// file: hello.ts
import { iii } from "iii-sdk";
async function greet(payload: { name?: string }) {
const name = payload.name ?? "world";
await iii.logInfo(`Greeting ${name}`);
return { message: `Hello, ${name}!` };
}
await iii.registerFunction({
function_id: "hello::greet",
handler: greet,
description: "Return a greeting",
});
await iii.registerTrigger({
type: "http",
function_id: "hello::greet",
config: { api_path: "/hello", http_method: "POST" },
});
await new Promise(() => {});
Source reference: Core registration logic resides in sdk/packages/node/iii/src/iii.ts.
Rust Implementation
Add with: cargo add iii-sdk
// file: hello.rs
use iii_sdk::{
register::{RegisterFunction, RegisterTrigger},
III,
error::Result,
types::HttpMethod,
};
#[iii::function]
async fn greet(payload: serde_json::Value) -> Result<serde_json::Value> {
let name = payload
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("world");
III::log_info(&format!("Greeting {}", name)).await?;
Ok(serde_json::json!({ "message": format!("Hello, {}!", name) }))
}
#[tokio::main]
async fn main() -> Result<()> {
III::register_function(
RegisterFunction::new("hello::greet", greet)
.description("Return a greeting"),
)
.await?;
III::register_trigger(
iii_sdk::trigger::HttpTrigger::new("/hello", HttpMethod::Post)
.for_function("hello::greet"),
)
.await?;
futures::future::pending::<()>().await;
Ok(())
}
Source reference: The RegisterFunction and RegisterTrigger builders are defined in sdk/packages/rust/iii/src/register.rs and exposed through sdk/packages/rust/iii/src/lib.rs.
Core Differences: Type Systems, Error Handling, and Async Models
While the underlying protocol remains identical across SDKs, the developer experience differs significantly in three key areas.
Type Safety and Serialization
- Python: Uses dynamic typing with runtime dictionary validation. Payloads are plain Python
dictobjects serialized to JSON by the SDK. - TypeScript: Provides compile-time structural typing via TypeScript interfaces (
IIIRegisterFunction,IIITriggerConfig) with JSON serialization handled transparently. - Rust: Enforces compile-time type safety using
serde_derivefor zero-cost serialization. Theiii::functionprocedural macro generates boilerplate at compile time.
Error Handling Patterns
- Python SDK: Propagates errors through exceptions. Callers wrap SDK calls in
try/exceptblocks catchingiii.errors.IIIError. - TypeScript SDK: Returns rejected
Promiseobjects on failure, allowing standard.catch()ortry/catchwith async/await. - Rust SDK: Returns explicit
Result<T, IIIError>types, requiring callers to handle errors viamatch,if let, or the?operator.
Concurrency and Runtime
- Python: Built on
asyncioevent loops with coroutine-based concurrency. - TypeScript: Uses the JavaScript event loop with
Promiseand async/await syntax. The browser SDK adds WebSocket connection management. - Rust: Compatible with both
tokioandasync-stdruntimes, offering true parallelism through OS threads combined with async tasks.
File Structure and Source References
Understanding the layout of the iii-hq/iii repository helps when debugging or extending SDK functionality.
| SDK | Core Module | Registration Logic | Observability | Example Usage |
|---|---|---|---|---|
| Python | sdk/packages/python/iii/src/iii/iii.py |
register_function, register_trigger functions in iii.py |
sdk/packages/python/iii/src/iii/log.py |
sdk/packages/python/iii-example/src/iii_function_example.py |
| TypeScript | sdk/packages/node/iii/src/iii.ts |
registerFunction, registerTrigger exports in iii.ts |
sdk/packages/node/iii/src/logger.ts |
Browser/Node tests in sdk/packages/node/iii-example/ |
| Rust | sdk/packages/rust/iii/src/lib.rs |
Builder structs in src/register.rs |
src/logger.rs with observability feature |
sdk/packages/rust/iii-example/src/http_example.rs |
All three SDKs transmit messages using the protocol definitions in engine/src/protocol.rs, ensuring wire-format compatibility regardless of language choice.
Which SDK Should You Choose?
Select the SDK that aligns with your existing infrastructure and performance requirements.
-
Choose Python when integrating with existing Python services or data science workflows. The
asynciopattern integrates cleanly with FastAPI or other async Python frameworks, and the PyPI distribution (pip install iii-sdk) requires no compilation step. -
Choose TypeScript for full-stack JavaScript applications or when you need browser-based worker execution. The
iii-browser-sdkprovides a lightweight bundle with WebSocket auto-reconnection, while the Node SDK (pnpm install iii-sdk) works seamlessly with Express or Next.js backends. -
Choose Rust for performance-critical workers requiring minimal memory footprint and compile-time safety guarantees. The crate (
cargo add iii-sdk) produces native binaries with zero-cost abstractions and strong typing viaserde.
Summary
- All three SDKs expose identical high-level APIs (function registration, trigger binding, streaming, and logging) but differ in language-specific ergonomics.
- Python uses
asynciocoroutines with exception-based error handling and dynamic typing. - TypeScript provides Promise-based async/await with compile-time interfaces and browser compatibility.
- Rust offers zero-cost abstractions with
Result<T, Error>returns andserde-based serialization. - Installation differs by ecosystem:
pip install iii-sdk(Python),pnpm install iii-sdk(TypeScript), andcargo add iii-sdk(Rust). - Source code for each SDK resides in
sdk/packages/python/,sdk/packages/node/, andsdk/packages/rust/respectively.
Frequently Asked Questions
Can I mix SDKs in the same iii deployment?
Yes. The iii engine treats all SDKs identically on the wire because they use the same WebSocket protocol defined in engine/src/protocol.rs. You can register functions in Rust, trigger them from TypeScript clients, and process results in Python workers within the same application.
Do all SDKs support the same trigger types?
Yes. All three SDKs support HTTP endpoints, cron schedules, pub/sub topics, and custom triggers. However, the TypeScript SDK specifically provides additional browser-oriented utilities like iii-browser-sdk for WebSocket connection management, while the Rust SDK offers strongly-typed trigger builders (e.g., HttpTrigger::new) for compile-time validation.
How does error propagation differ between the SDKs?
Python raises iii.errors.IIIError exceptions that must be caught with try/except. TypeScript returns rejected Promises that can be handled with .catch() or try/catch. Rust returns Result<T, IIIError> enums, requiring explicit error handling with the ? operator or pattern matching. All three propagate error details back to the engine logs regardless of language.
Which SDK offers the best performance for high-throughput workers?
The Rust SDK provides the best raw performance due to zero-cost abstractions, lack of garbage collection, and compile-time optimizations. However, the Python and TypeScript SDKs are sufficient for I/O-bound workloads and offer faster development cycles. For CPU-intensive tasks, Rust's native binary execution in sdk/packages/rust/iii/src/lib.rs minimizes latency and memory overhead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →