generate_client!() { /* proc-macro */ }Expand description
Generate a type-safe API client for an OpenAPI endpoint. This macro is designed to work within an agent-based API automation system that uses RAG (Retrieval Augmented Generation) to find and execute relevant API endpoints.
§System Overview
The typical workflow:
- OpenAPI specs are downloaded and stored in the database
- Endpoints are extracted and embedded for RAG retrieval
- When a natural language task arrives, relevant endpoints are retrieved
- This macro generates type-safe clients for those endpoints
§Usage Example
use serde::{Serialize, Deserialize};
use pgvector::Vector;
use uuid::Uuid;
// Define your custom error type
#[derive(Debug, thiserror::Error)]
pub enum AgentError {
#[error("API request failed: {0}")]
Request(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
// ... other error variants as needed
}
// Define your request and response types
#[derive(Debug, Serialize)]
struct SearchUsersParams {
query: String,
max_results: i32,
include_inactive: bool,
}
#[derive(Debug, Deserialize)]
struct UserSearchResponse {
users: Vec<User>,
total_count: i32,
page_token: Option<String>,
}
// Generate the client with your custom error type
generate_client!(
UserSearchClient, // Name for the generated client
"/api/v1/users/search", // Endpoint path
"POST", // HTTP method
SearchUsersParams, // Parameters type
UserSearchResponse, // Response type
AgentError // Your custom error type
);
// Example usage in an agent system
struct Agent {
openai: OpenAIClient,
db: PgPool,
}
impl Agent {
async fn execute_task(&self, task: &str) -> Result<serde_json::Value, AgentError> {
// Find relevant endpoint using RAG
let endpoint = find_relevant_endpoint(&self.db, task).await?;
// Generate parameters using LLM
let params = self.generate_parameters(task).await?;
// Execute the API call using our generated client
let client = UserSearchClient::new("https://api.example.com".to_string());
let response = client.execute(params).await?;
Ok(serde_json::to_value(response)?)
}
}§Parameters
client_name: The name of the generated client structpath: The endpoint path template (e.g., “/users/{id}/posts”)method: The HTTP method as a string (e.g., “GET”, “POST”)params_type: The request parameters type (must implement Serialize)response_type: The response type (must implement Deserialize)error_type: Your custom error type that implements Fromreqwest::Error and From<serde_json::Error>
§Generated Client
The macro generates a client struct with:
- Constructor for base URL configuration
- Type-safe execute method that handles:
- Path parameter substitution
- Request body serialization
- Response deserialization
- Error conversion to your custom type
§Error Handling
The generated client returns Result<T, E> where E is your custom error type.
Your error type must implement:
impl From<reqwest::Error> for YourErrorType { ... }
impl From<serde_json::Error> for YourErrorType { ... }Common error cases that will be converted to your error type:
- URL construction failures
- Network errors from reqwest
- Non-200 HTTP responses
- JSON serialization/deserialization errors