| Crates.io | openrouter_api |
| lib.rs | openrouter_api |
| version | 0.1.6 |
| created_at | 2025-02-05 17:41:39.321533+00 |
| updated_at | 2025-06-11 01:43:04.867381+00 |
| description | A Rust client library for the OpenRouter API |
| homepage | |
| repository | https://github.com/socrates8300/openrouter_api |
| max_upload_size | |
| id | 1544480 |
| size | 656,528 |
A production-ready Rust client for the OpenRouter API with comprehensive security, ergonomic design, and extensive testing. The library uses a type‑state builder pattern for compile-time configuration validation, ensuring robust and secure API interactions.
zeroize crate for enhanced securityfrom_api_key(), from_env(), quick(), and production() methodsOPENROUTER_API_KEY or OR_API_KEY environment variablesAdd the following to your project's Cargo.toml:
cargo add openrouter_api
# With optional tracing support for better error logging
cargo add openrouter_api --features tracing
Available Features:
rustls (default): Use rustls for TLSnative-tls: Use system TLStracing: Enhanced error logging with tracing supportEnsure that you have Rust installed (tested with Rust v1.83.0) and that you're using Cargo for building and testing.
use openrouter_api::{OpenRouterClient, Result};
use openrouter_api::types::chat::{ChatCompletionRequest, Message};
#[tokio::main]
async fn main() -> Result<()> {
// Quick setup from environment variable (OPENROUTER_API_KEY)
let client = OpenRouterClient::from_env()?;
// Or directly from API key
// let client = OpenRouterClient::from_api_key("sk-or-v1-...")?;
let request = ChatCompletionRequest {
model: "openai/gpt-4o".to_string(),
messages: vec![Message {
role: "user".to_string(),
content: "Hello, world!".to_string(),
name: None,
tool_calls: None,
}],
stream: None,
response_format: None,
tools: None,
provider: None,
models: None,
transforms: None,
};
let response = client.chat()?.chat_completion(request).await?;
if let Some(choice) = response.choices.first() {
println!("Response: {}", choice.message.content);
}
Ok(())
}
use openrouter_api::{OpenRouterClient, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Production-ready client with optimized settings
let client = OpenRouterClient::production(
"sk-or-v1-...", // API key
"My Production App", // App name
"https://myapp.com" // App URL
)?;
// Client is now configured with:
// - 60 second timeout
// - 5 retries with exponential backoff
// - Proper headers for app identification
// Use the client...
Ok(())
}
use openrouter_api::{OpenRouterClient, Result};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<()> {
// Full control over client configuration
let client = OpenRouterClient::new()
.skip_url_configuration() // Use default OpenRouter URL
.with_timeout_secs(120) // 2-minute timeout
.with_retries(3, 500) // 3 retries, 500ms initial backoff
.with_http_referer("https://myapp.com")
.with_site_title("My Application")
.with_api_key("sk-or-v1-...")?;
// Ready to use
Ok(())
}
use openrouter_api::{OpenRouterClient, utils, Result};
use openrouter_api::models::provider_preferences::{DataCollection, ProviderPreferences, ProviderSort};
use openrouter_api::types::chat::{ChatCompletionRequest, Message};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<()> {
// Load API key from environment variables
let api_key = utils::load_api_key_from_env()?;
// Build the client
let client = OpenRouterClient::new()
.with_base_url("https://openrouter.ai/api/v1/")?
.with_api_key(api_key)?;
// Create provider preferences
let preferences = ProviderPreferences::new()
.with_order(vec!["OpenAI".to_string(), "Anthropic".to_string()])
.with_allow_fallbacks(true)
.with_data_collection(DataCollection::Deny)
.with_sort(ProviderSort::Throughput);
// Create a request builder with provider preferences
let request_builder = client.chat_request_builder(vec![
Message {
role: "user".to_string(),
content: "Hello with provider preferences!".to_string(),
name: None,
tool_calls: None,
},
]);
// Add provider preferences and build the payload
let payload = request_builder
.with_provider_preferences(preferences)?
.build();
// The payload now includes provider preferences!
println!("Request payload: {}", serde_json::to_string_pretty(&payload)?);
Ok(())
}
use openrouter_api::{MCPClient, Result};
use openrouter_api::mcp_types::{
ClientCapabilities, GetResourceParams, ToolCallParams,
MCP_PROTOCOL_VERSION
};
#[tokio::main]
async fn main() -> Result<()> {
// Create a new MCP client
let client = MCPClient::new("https://mcp-server.example.com/mcp")?;
// Initialize the client with client capabilities
let server_capabilities = client.initialize(ClientCapabilities {
protocolVersion: MCP_PROTOCOL_VERSION.to_string(),
supportsSampling: Some(true),
}).await?;
println!("Connected to MCP server with capabilities: {:?}", server_capabilities);
// Get a resource from the MCP server
let resource = client.get_resource(GetResourceParams {
id: "document-123".to_string(),
parameters: None,
}).await?;
println!("Retrieved resource: {}", resource.content);
// Call a tool on the MCP server
let result = client.tool_call(ToolCallParams {
id: "search-tool".to_string(),
parameters: serde_json::json!({
"query": "Rust programming"
}),
}).await?;
println!("Tool call result: {:?}", result.result);
Ok(())
}
use openrouter_api::{OpenRouterClient, utils, Result};
use openrouter_api::types::completion::CompletionRequest;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<()> {
// Load API key from environment
let api_key = utils::load_api_key_from_env()?;
// Build the client
let client = OpenRouterClient::new()
.with_base_url("https://openrouter.ai/api/v1/")?
.with_api_key(api_key)?;
// Create a text completion request
let request = CompletionRequest {
model: "openai/gpt-3.5-turbo-instruct".to_string(),
prompt: "Once upon a time".to_string(),
// Additional generation parameters
extra_params: json!({
"temperature": 0.8,
"max_tokens": 50
}),
};
// Invoke the text completion endpoint
let completions_api = client.completions()?;
let response = completions_api.text_completion(request).await?;
// Print out the generated text
if let Some(choice) = response.choices.first() {
println!("Text Completion: {}", choice.text);
}
Ok(())
}
use openrouter_api::{OpenRouterClient, utils, Result};
use openrouter_api::types::chat::{ChatCompletionRequest, Message};
use futures::StreamExt;
use std::io::Write;
#[tokio::main]
async fn main() -> Result<()> {
// Load API key from environment
let api_key = utils::load_api_key_from_env()?;
// Build the client
let client = OpenRouterClient::new()
.with_base_url("https://openrouter.ai/api/v1/")?
.with_api_key(api_key)?;
// Create a chat completion request with streaming enabled
let request = ChatCompletionRequest {
model: "openai/gpt-4o".to_string(),
messages: vec![Message {
role: "user".to_string(),
content: "Tell me a story.".to_string(),
name: None,
tool_calls: None,
}],
stream: Some(true),
response_format: None,
tools: None,
provider: None,
models: None,
transforms: None,
};
// Invoke the streaming chat completion endpoint
let chat_api = client.chat()?;
let mut stream = chat_api.chat_completion_stream(request);
// Process the stream - accumulating content and tracking usage
let mut total_content = String::new();
while let Some(chunk) = stream.next().await {
match chunk {
Ok(c) => {
if let Some(choice) = c.choices.first() {
if let Some(content) = &choice.delta.content {
print!("{}", content);
total_content.push_str(content);
std::io::stdout().flush().unwrap();
}
}
// Check for usage information in final chunk
if let Some(usage) = c.usage {
println!("\nUsage: {} prompt + {} completion = {} total tokens",
usage.prompt_tokens, usage.completion_tokens, usage.total_tokens);
}
},
Err(e) => eprintln!("Error during streaming: {}", e),
}
}
println!();
Ok(())
}
The library includes a client implementation for the Model Context Protocol, which is an open protocol that standardizes how applications provide context to LLMs.
Key features of the MCP client include:
// Create an MCP client connected to a server
let client = MCPClient::new("https://mcp-server.example.com/mcp")?;
// Initialize with client capabilities
let server_capabilities = client.initialize(ClientCapabilities {
protocolVersion: "2025-03-26".to_string(),
supportsSampling: Some(true),
}).await?;
// Access resources from the server
let resource = client.get_resource(GetResourceParams {
id: "some-resource-id".to_string(),
parameters: None,
}).await?;
See the Model Context Protocol specification for more details.
This is a production-ready library with comprehensive functionality:
from_env(), from_api_key(), production(), quick()Contributions are welcome! Please open an issue or submit a pull request with your ideas or fixes. Follow the code style guidelines and ensure that all tests pass.
Distributed under either the MIT license or the Apache License, Version 2.0. See LICENSE for details.
Version: 0.1.6 • License: MIT / Apache‑2.0
The openrouter_api crate is a comprehensive client for interacting with the OpenRouter API and Model Context Protocol servers. It provides strongly‑typed endpoints for chat completions, text completions, web search, and MCP connections. The crate is built using asynchronous Rust and leverages advanced patterns for safe and flexible API usage.
Type‑State Client Configuration: The client is built using a type‑state pattern to ensure that required parameters are set before making any API calls.
Provider Preferences: Strongly-typed configuration for model routing, fallbacks, and provider selection.
Asynchronous Streaming: Support for streaming responses via asynchronous streams.
Model Context Protocol: Client implementation for connecting to MCP servers to access resources, tools, and prompts.
Error Handling & Validation: Comprehensive error handling with detailed context and validation utilities.
The crate is organized into several modules:
client: Type-state client implementation with builder patternapi: API endpoint implementations (chat, completions, web search, etc.)models: Domain models for structured outputs, provider preferences, toolstypes: Type definitions for requests and responsesmcp: Model Context Protocol client implementationerror: Centralized error handlingutils: Utility functions and helpers// Quick setup (recommended for most use cases)
let client = OpenRouterClient::from_env()?;
// Production setup with optimized settings
let client = OpenRouterClient::production(
"sk-or-v1-...",
"My App",
"https://myapp.com"
)?;
// Full control with type-state pattern
let client = OpenRouterClient::new()
.with_base_url("https://openrouter.ai/api/v1/")?
.with_timeout(Duration::from_secs(30))
.with_http_referer("https://your-app.com/")
.with_api_key(std::env::var("OPENROUTER_API_KEY")?)?;
// Basic chat completion
let response = client.chat()?.chat_completion(
ChatCompletionRequest {
model: "openai/gpt-4o".to_string(),
messages: vec![Message {
role: "user".to_string(),
content: "Explain quantum computing".to_string(),
name: None,
tool_calls: None,
}],
stream: None,
response_format: None,
tools: None,
provider: None,
models: None,
transforms: None,
}
).await?;
// Define a function tool
let weather_tool = Tool::Function {
function: FunctionDescription {
name: "get_weather".to_string(),
description: Some("Get weather information for a location".to_string()),
parameters: serde_json::json!({
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and state"
}
},
"required": ["location"]
}),
}
};
// Make a request with tool calling enabled
let response = client.chat()?.chat_completion(
ChatCompletionRequest {
model: "openai/gpt-4o".to_string(),
messages: vec![Message {
role: "user".to_string(),
content: "What's the weather in Boston?".to_string(),
name: None,
tool_calls: None,
}],
tools: Some(vec![weather_tool]),
// other fields...
stream: None,
response_format: None,
provider: None,
models: None,
transforms: None,
}
).await?;
// Create an MCP client
let mcp_client = MCPClient::new("https://mcp-server.example.com/mcp")?;
// Initialize with client capabilities
let server_capabilities = mcp_client.initialize(ClientCapabilities {
protocolVersion: MCP_PROTOCOL_VERSION.to_string(),
supportsSampling: Some(true),
}).await?;
// Access a resource from the MCP server
let resource = mcp_client.get_resource(GetResourceParams {
id: "document-123".to_string(),
parameters: None,
}).await?;
match client.chat()?.chat_completion(request).await {
Ok(response) => {
println!("Success: {}", response.choices[0].message.content);
},
Err(e) => match e {
Error::ApiError { code, message, .. } => {
eprintln!("API Error ({}): {}", code, message);
},
Error::HttpError(ref err) if err.is_timeout() => {
eprintln!("Request timed out!");
},
Error::ConfigError(msg) => {
eprintln!("Configuration error: {}", msg);
},
_ => eprintln!("Other error: {:?}", e),
}
}
Use the Type‑State Pattern: Let the compiler ensure your client is properly configured.
Set Appropriate Timeouts & Headers: Configure reasonable timeouts and identify your application.
Handle Errors Appropriately: Implement proper error handling for each error type.
Use Provider Preferences: Configure provider routing for optimal model selection.
Secure Your API Keys: Store keys in environment variables or secure storage.