#codegen #schema #derive-codegen #google-ai

macro google-ai-schema-derive

Type-safe schema generation for Google AI API interactions

3 releases

0.1.2 Aug 11, 2025
0.1.1 May 26, 2025
0.1.0 May 7, 2025

#4 in #derive-codegen

Download history 25/week @ 2025-06-23 44/week @ 2025-06-30 205/week @ 2025-07-07 341/week @ 2025-07-14 21/week @ 2025-07-21 25/week @ 2025-07-28 17/week @ 2025-08-04 175/week @ 2025-08-11 46/week @ 2025-08-18 69/week @ 2025-08-25 48/week @ 2025-09-01 33/week @ 2025-09-08 62/week @ 2025-09-15 89/week @ 2025-09-22 50/week @ 2025-09-29 55/week @ 2025-10-06

260 downloads per month
Used in google-ai-rs

MIT license

120KB
2.5K SLoC

crates.io Documentation CI Status

🧬 google-ai-schema-derive: Type-Safe Gemini Schemas in Rust

Generate bulletproof JSON schemas for Google AI with derive macros -
Because guessing games don't belong in production AI systems!

[dependencies]
google-ai-schema-derive = "0.1.2"

⚡️ 10-Second Schema Generation

#[derive(AsSchema, Deserialize)]
#[schema(description = "Social media post analysis")]
struct PostAnalysis {
    #[schema(description = "Sentiment score (-1 to 1)")]
    sentiment: f32,
    
    #[schema(rename = "topics", description = "Detected topics")]
    hashtags: Vec<String>,
}

// Automatically generates Gemini-compatible schema:
/*
{
  "type": "object",
  "description": "Social media post analysis",
  "properties": {
    "sentiment": {
      "type": "number",
      "format": "float",
      "description": "Sentiment score (-1 to 1)"
    },
    "topics": {
      "type": "array",
      "items": {"type": "string"},
      "description": "Detected topics"
    }
  },
  "required": ["sentiment", "topics"]
}
*/

🚀 Why Developers Love This

1. Type Safety Meets AI Magic

#[derive(AsSchema, Deserialize)]
struct FinancialReport {
    #[schema(description = "Year-over-year growth %")]
    yoy_growth: f64,
    
    #[schema(
        description = "Key performance indicators",
        min_items = 3,
        max_items = 5
    )]
    kpis: Vec<String>,
}

// Compile-time validation

2. Serde Superpowers

#[derive(AsSchema, Serialize)]
#[schema(rename_all = "camelCase")]
struct UserProfile {
    #[serde(rename = "fullName")] // Mirrored in schema!
    name: String,
    
    #[schema(skip)] // Hidden from schema, kept in Serde
    internal_id: Uuid,
}

3. Real-World AI Schemas Made Easy

News Article Analysis:

#[derive(AsSchema, Deserialize)]
#[schema(description = "News article metadata extraction")]
struct ArticleMeta {
    #[schema(description = "ISO language code")]
    language: String,
    
    #[schema(
        description = "People/organizations mentioned",
        min_items = 1
    )]
    entities: Vec<String>,
    
    #[schema(as_schema = "date_schema")]
    publish_date: i64,
}

fn date_schema() -> Schema {
    Schema {
        r#type: SchemaType::String as i32,
        ..Default::default()
    }
}

🛠️ Schema Crafting Toolkit

Core Attributes Cheat Sheet

Struct-Level Magic:

#[schema(
    description = "E-commerce product listing",
    rename_all = "snake_case",
    nullable   // Whole struct can be null
)]
struct Product {
    // ...
}

Field-Level Control:

#[schema(
    description = "Price in USD cents",
    r#type = "Integer",
    format = "int64",
    required  // Force include in required[]
)]
price: u64,

#[schema(
    as_schema = "custom_image_schema",  // Full override
    skip      // Exclude from schema
)]
hero_image: Vec<u8>

Enum Strategies

Simple Variants → String Enum:

#[derive(AsSchema)]
enum ContentRating {
    Safe,
    Mature,
    Explicit
}

// Generates: {"type": "string", "enum": ["Safe", "Mature", "Explicit"]}

Complex Variants → Tagged Union:

#[derive(AsSchema)]
enum APIResponse {
    Success { data: String },
    Error { code: u16, message: String }
}

/*
{
  "type": "object",
  "properties": {
    "Success": { /* data schema */ },
    "Error": { /* error schema */ }
  }
}
*/

🚨 Compliance First

Enforced Best Practices

#[derive(AsSchema)]
struct MedicalReport {
    diagnosis: String,
    
    #[schema(r#type = "string", format = "float")] // COMPILE ERROR: Type mismatch
    probability: f32
}

Gemini-Specific Rules

  • Type-format compatibility checked
  • No recursive types

📦 Perfect Pairing

Works seamlessly with google-ai-rs main crate:

use google_ai_rs::{AsSchema, TypedModel};

#[derive(AsSchema, Deserialize)]
struct LegalClause {
    #[schema(description = "Clause text in Markdown")]
    text: String,
    #[schema(description = "Applicable jurisdictions")]
    regions: Vec<String>,
}

let model = TypedModel::<LegalClause>::new(&client, "gemini-pro");
let clause = model.generate_content("Generate GDPR data processing clause").await?;

Dependencies

~175–590KB
~14K SLoC