Generated Specs And Clients
The service macros use the Rust API definition to generate machine-readable contracts and client helpers.
OpenRPC
jsonrpc_service! can generate OpenRPC when the service enables
openrpc: true or openrpc: { output: "path/to/file.json" }.
pub fn generate_userservice_openrpc() -> serde_json::Value;
pub fn generate_userservice_openrpc_to_file() -> Result<(), std::io::Error>;
The document includes method names, request and response schemas, auth
extensions, flattened x-permissions, grouped x-permission-groups, and
version metadata for versioned methods.
OpenAPI
rest_service! and file_service! can generate OpenAPI with openapi: true
or a custom output path.
pub fn generate_userservice_openapi() -> serde_json::Value;
pub fn generate_userservice_openapi_to_file() -> std::io::Result<()>;
REST operations include routes, HTTP methods, JSON schemas, bearer auth
requirements, flattened x-permissions, and grouped x-permission-groups.
File-service operations also include
multipart schemas, binary download responses, and x-ras-file metadata for
upload limits, part policies, content types, and range support.
Rust Clients
Enabling a service macro crate’s client feature emits typed Rust clients that
can be constructed with build_with_transport(...). Enabling the macro crate’s
reqwest feature also emits the default reqwest-backed build().
The examples keep API definitions in separate API crates and expose API-crate
client features that forward to the macro crate’s reqwest feature, so
server and browser crates can depend on the same contract while selecting
different generated surfaces. Test-only or in-process clients can instead
forward only the macro crate’s client feature and depend directly on
ras-transport-core.
For browser targets, compile client crates with --target wasm32-unknown-unknown
and enable only the API crate’s client-side feature set. See:
Build-Time Spec Generation
Backend crates can emit OpenRPC or OpenAPI during compilation from build.rs.
That keeps generated client input tied to the same Rust API contract used by
the server.
fn main() {
rest_api::generate_userservice_openapi_to_file()
.expect("generate OpenAPI");
}
The REST and file-service examples write specs under target/openapi. A
frontend build can then point its OpenAPI generator at that file.
TypeScript Call Shape
The generated TypeScript fetch clients used in the examples accept one config object per call:
await postUsers({
baseUrl: 'http://localhost:3000/api/v1',
headers: { Authorization: `Bearer ${token}` },
path: { id: 'user-123' },
query: { include_archived: false },
body: { name: 'Alice' },
});
Only include the fields the operation needs. Public GET calls often need only
baseUrl; protected uploads usually include headers and body.
Versioned Methods And Endpoints
JSON-RPC and REST macros support opt-in compatibility definitions. A canonical operation can declare legacy wire names, legacy request/response types, and a migration type. The generated server accepts both shapes while the service implementation only handles the canonical Rust type.
Use versioning when a deployed client still depends on an old wire contract and the server can safely migrate requests and responses at the API boundary.