You know that moment when you finally add a new endpoint to your Rust backend? Except it’s not a moment of triumph. It’s an hour of wrestling with Axum’s type system, re-running cargo test to generate OpenAPI docs, installing a third-rate TypeScript converter, and then spending another hour fixing the generated code. You’re not building features. You’re fighting your tools.
I’ve been there. For three years, I built APIs with Rust and TypeScript. Every new endpoint was a reminder that the very tools promising productivity were actually stealing it. The more type-safe you make your system, the more boilerplate you create to keep the types happy.
Then I discovered something that changed everything. It wasn’t a new framework. It was a return to an old idea: APIs as first-class citizens. Not through more macros or complex abstractions, but through a simple Interface Definition Language (IDL) that decouples the contract from the implementation.
Let me show you what I mean. The problem started with Axum. Axum is powerful, but its type system is opinionated in a way that makes every endpoint a type puzzle. You need to understand extractors, responses, and state management before you can write a single line of business logic. Combined with utoipa for OpenAPI generation—which requires a separate cargo test step—the workflow becomes a nightmare of inconsistency.
Then there’s the TypeScript side. Converting OpenAPI to TypeScript is supposed to be a solved problem, but every tool I tried produced code that was either unusable or required heavy manual tweaking. The synchronization between Rust and TypeScript was a constant source of bugs.
Here’s the twist: the very features that attracted me to Rust—type safety, zero-cost abstractions, and a powerful macro system—were becoming the primary source of friction. I was building abstraction layers to hide the complexity that the framework introduced. That’s when I realized: the framework itself was the problem.
So I built XIDL. It’s a tool that lets you define your API in a lightweight proto-like file, and generates Rust traits, OpenAPI specs, and TypeScript types—all from a single source of truth. The key insight: the interface contract should be separate from the implementation details. You write the API once, and the code generation handles the rest.
No more fighting Axum’s complex types. XIDL generates generic async traits that hide the HTTP complexity inside the generated code. You implement the trait, and the HTTP server works automatically. The OpenAPI documentation is generated during build time, not during a separate test step. And the TypeScript output is consistent because the interface behavior is strictly defined using RFCs.
I also added an LSP for real-time preview of the OpenAPI interface via Scalar, so you can test HTTP calls directly from your browser during development.
The best code is the code you never write. That’s the philosophy behind XIDL. It’s not about adding more layers—it’s about removing them. It’s about giving developers back the time they waste on boilerplate and type gymnastics.
If you’re a full-stack developer who’s tired of the API synchronization game, try writing your next project with an IDL. You’ll be surprised how much of your frustration disappears when you stop fighting your tools and start building.
FAQ
Q: Why not just use gRPC or TypeSpec?
A: gRPC and TypeSpec are great, but they come with their own baggage—heavy runtime, steep learning curves, and limited language support. XIDL is intentionally lightweight, generating pure Rust traits and TypeScript types without runtime dependencies. It's designed for web developers who want simplicity over enterprise features.
Q: What does this mean for my existing project?
A: You can adopt XIDL incrementally. Define your new endpoints in the IDL, and gradually migrate old ones. The generated code integrates with Axum, Actix, or any other framework via the async trait pattern. It's a drop-in replacement for your current boilerplate.
Q: Isn't this just adding another abstraction layer?
A: Yes, but it's a thin layer that ships the complexity to compile time. Instead of fighting runtime type errors and inconsistent code generation, you catch issues at the IDL level. The abstraction is the point—it's a contract that eliminates the need for all the other abstractions.