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

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 the dependencies used by this example:

cargo add reflectapi --features builder,axum
cargo add serde --features derive
cargo add serde_json
cargo add tokio --features full
cargo add axum

Define Your API

Replace the contents of src/main.rs:

// This is a complete example for src/main.rs

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.json", schema_json)?;

    println!("✅ API schema generated at reflectapi.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.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

This installs the reflectapi binary. Then generate a TypeScript client:

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

Use Your Generated Client

The generated TypeScript client will be fully typed:

import { client } from "./clients/typescript/generated";

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

// Create a user. Generated methods take typed input and typed headers.
const created = await c.users.create({
  name: 'Bob',
  email: 'bob@example.com'
}, {});

if (created.is_ok()) {
  console.log(created.unwrap_ok());
}

That's it!