Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

reflectapi is a library and a toolkit for writing web API services in Rust and generating compatible clients, delivering great development experience and efficiency.

Why reflectapi?

https://rustforgeconf.com/talks

Core Philosophy

  1. Rust code first definition of the API interface
  2. Full respect for all serde attributes
  3. Extensible at many places

Ready to Start?

Head over to Quick Start to build your first API with reflectapi!

Quick Start

This guide will have you up and running with reflectapi in under 5 minutes.

Prerequisites

  • Rust 1.78.0 or later
  • Basic familiarity with Rust and web APIs

Create a New Project

cargo new my-api
cd my-api

Add Dependencies

Add reflectapi to your Cargo.toml:

[dependencies]
reflectapi = { version = "0.15", features = ["builder", "axum"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
axum = "0.7"

Define Your API

Replace the contents of src/main.rs:

// This is a complete example for src/main.rs
// Add these dependencies to your Cargo.toml first:
// [dependencies]
// reflectapi = { version = "0.15", features = ["builder", "axum"] }
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
// tokio = { version = "1.0", features = ["full"] }

use reflectapi::{Builder, Input, Output};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Input, Output)]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[derive(Serialize, Deserialize, Input)]
struct CreateUserRequest {
    name: String,
    email: String,
}

// Handler functions need specific signatures for reflectapi
async fn create_user(_state: (), req: CreateUserRequest, _headers: ()) -> User {
    // In a real app, you'd save to a database
    User { 
        id: 1, 
        name: req.name, 
        email: req.email 
    }
}

async fn get_user(_state: (), id: u32, _headers: ()) -> Option<User> {
    // In a real app, you'd query a database
    if id == 1 {
        Some(User {
            id: 1,
            name: "Alice".to_string(),
            email: "alice@example.com".to_string(),
        })
    } else {
        None
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build the API schema
    let builder = Builder::new()
        .name("User API")
        .description("A simple user management API")
        .route(create_user, |route| {
            route
                .name("users.create")
                .description("Create a new user")
        })
        .route(get_user, |route| {
            route
                .name("users.get")
                .description("Get a user by ID")
        });

    let (schema, routers) = builder.build()?;
    
    // Save schema for client generation
    let schema_json = serde_json::to_string_pretty(&schema)?;
    std::fs::write("reflectapi-schema.json", schema_json)?;
    
    println!("✅ API schema generated at reflectapi-schema.json");
    
    // Start the HTTP server
    let app_state = (); // No state needed for this example
    let axum_app = reflectapi::axum::into_router(app_state, routers, |_name, r| r);
    
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    println!("🚀 Server running on http://0.0.0.0:3000");
    println!("📖 Ready to generate clients!");
    
    axum::serve(listener, axum_app).await?;
    
    Ok(())
}

Run Your API Server

cargo run

You should see:

✅ API schema generated at reflectapi-schema.json
🚀 Server running on http://0.0.0.0:3000
📖 Ready to generate clients!

🎉 Congratulations! You now have a running API server and generated client-ready schema.

Generate a Client

First, install the CLI:

cargo install reflectapi-cli

Then generate a TypeScript client:

mkdir clients
reflectapi-cli codegen --language typescript --schema reflectapi-schema.json --output clients/typescript

Use Your Generated Client

The generated TypeScript client will be fully typed:

import { client } from './clients/typescript';

const c = client('http://localhost:3000');

// Create a user - fully type-safe!
const newUser = await c.users.create({
  name: 'Bob',
  email: 'bob@example.com'
});

// Get a user
const user = await c.users.get(1);

That's it!

Installation

Get reflectapi up and running in minutes.

Basic Setup

cargo add reflectapi --features builder,axum,json,chrono

CLI Tool

Install the CLI tool to generate client libraries:

cargo install reflectapi-cli --help

Next Steps

Client Generation

reflectapi automatically generates type-safe client libraries for multiple programming languages from your Rust API server. This section covers how to generate and use clients in different languages.

Supported Languages

LanguageStatus
TypeScript✅ Stable
Rust✅ Stable
Python✅ Experiemental

Code Generation Workflow

See demo project setup https://github.com/thepartly/reflectapi/tree/main/reflectapi-demo

  1. Define your API server using reflectapi traits and builder
  2. Generate schema as JSON from your Rust application
  3. Run the CLI to generate client libraries
  4. Use the clients in your applications with full type safety
# Generate schema (from your Rust app)
cargo run  # Your app should save reflectapi-schema.json

# Generate clients
cargo run reflectapi codegen --language typescript --schema reflectapi-schema.json --output clients/typescript
cargo run reflectapi codegen --language python --schema reflectapi-schema.json --output clients/python
cargo run reflectapi codegen --language rust --schema reflectapi-schema.json --output clients/rust

Common Features

All generated clients share these characteristics:

Type Safety

  • Native type definitions for each language
  • Compile-time or runtime type checking
  • IDE support with autocompletion

Extensibility

  • Default base client implementation is provided
  • Which can be replaced or extended with features, such opentelemetry instrumentation or playwrite tracing

Error Handling

  • Structured error types
  • Network error handling

Async Support

  • Modern async/await patterns

Documentation

  • Generated from your Rust documentation
  • Type information in IDE tooltips

HTTP Client Libraries

LanguageHTTP LibraryFeatures
TypeScriptfetch APINative browser/Node.js support
PythonhttpxAsync/sync, HTTP/2, connection pooling
RustreqwestAsync, HTTP/2, TLS, middleware

Serialization

LanguageSerializationValidation
TypeScriptJSON.parse/stringifyRuntime type checking
PythonPydanticSchema validation, type coercion
RustJSON or MessagePack (serde)Compile-time, zero-cost