Rust OpenAI SDK Alternative: Integrating with Fikra API
Overview
Fikra API provides an OpenAI-compatible chat-completions interface. While there is no official "Rust OpenAI SDK" that natively supports Fikra out of the box, you can use standard Rust HTTP clients (such as reqwest) to interact with the Fikra API using the same request/response structure as OpenAI's chat-completions endpoint.
This guide demonstrates how to configure a Rust application to call Fikra API, including streaming support and error handling.
Prerequisites
- Rust toolchain installed (
rustcandcargo). - A Fikra API key (
fk_live_...) obtained from the Fikra dashboard. - Basic familiarity with Rust async programming (using
tokioandreqwest).
Environment Variable Setup
Store your Fikra API key in an environment variable to avoid hardcoding secrets.
export FIKRA_API_KEY="fk_live_your_key_here"
Rust Integration Example
Below is a complete example using reqwest and tokio to send a non-streaming request to the Fikra API.
1. Add Dependencies
In your Cargo.toml, add:
[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", features = ["json", "stream"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
2. Implementation
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Serialize)]
struct ChatRequest {
model: String,
messages: Vec<Message>,
stream: bool,
}
#[derive(Serialize, Deserialize)]
struct Message {
role: String,
content: String,
}
#[derive(Deserialize)]
struct ChatResponse {
choices: Vec<Choice>,
}
#[derive(Deserialize)]
struct Choice {
message: Message,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api_key = env::var("FIKRA_API_KEY")
.expect("FIKRA_API_KEY environment variable not set");
let client = Client::new();
let request_body = ChatRequest {
model: "fikra-flash".to_string(),
messages: vec![
Message {
role: "user".to_string(),
content: "Hello, Fikra!".to_string(),
},
],
stream: false,
};
let response = client
.post("https://api.fikraapi.co.ke/v1/chat/completions")
.bearer_auth(api_key)
.json(&request_body)
.send()
.await?;
let status = response.status();
if !status.is_success() {
let error_text = response.text().await?;
eprintln!("Error: {} - {}", status, error_text);
return Ok(());
}
let chat_response: ChatResponse = response.json().await?;
println!("Response: {}", chat_response.choices[0].message.content);
Ok(())
}
Streaming Guidance
To enable streaming, set stream: true in the request body. The response will use Server-Sent Events (SSE). In Rust, you can read the response as a stream of bytes and parse the SSE lines.
// In the request body, set stream: true
let request_body = ChatRequest {
model: "fikra-flash".to_string(),
messages: vec![
Message {
role: "user".to_string(),
content: "Tell me a short story.".to_string(),
},
],
stream: true,
};
let response = client
.post("https://api.fikraapi.co.ke/v1/chat/completions")
.bearer_auth(api_key)
.json(&request_body)
.send()
.await?;
let mut stream = response.bytes_stream();
use futures::StreamExt;
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
// Parse SSE lines: lines starting with "data: " contain JSON chunks
for line in chunk.split(|&b| b == b'\n') {
if line.starts_with(b"data: ") {
let data = &line[6..];
if data == b"[DONE]" {
break;
}
// Deserialize the JSON chunk and extract the content delta
// Note: The structure for streaming chunks is similar to OpenAI's
// { "choices": [{ "delta": { "content": "..." } }] }
println!("{}", std::str::from_utf8(data).unwrap_or(""));
}
}
}
Common Errors
- 400 Bad Request: Malformed JSON, missing required fields, or invalid model alias. Check the model registry for available aliases.
- 401 Unauthorized: Invalid or missing API key. Ensure
Authorization: Bearer fk_live_...is correctly set. - 402 Payment Required: Insufficient token credits in your Fikra wallet. Top up via the Fikra dashboard.
- 429 Too Many Requests: Rate limit exceeded. Unverified accounts are limited to 30 RPM; trusted accounts to 100 RPM. Implement exponential backoff.
- 503 Service Unavailable: Temporary server issue. Retry with backoff.
Production Checklist
- API Key Management: Store
FIKRA_API_KEYin a secure environment variable or secrets manager. Never hardcode keys. - Rate Limiting: Implement client-side rate limiting and exponential backoff for 429 responses.
- Timeouts: Set appropriate connection and read timeouts for
reqwest. - Error Handling: Log and handle non-2xx responses gracefully. Distinguish between retryable (429, 503) and non-retryable (400, 401, 402) errors.
- Streaming: For streaming, ensure your client can handle partial responses and SSE parsing.
- Model Alias: Use only publicly listed Fikra aliases (e.g.,
fikra-flash,fikra-pro-20b). Check the model registry for availability. - Monitoring: Monitor API response times and error rates in production.
- Billing: Regularly check token credit balance to avoid 402 errors during peak usage.
James Miano
CTO & ML Engineer at Lacesse Ventures. James specializes in low-overhead LLM quantization processes, custom ternary weights architectures, and localized server optimization.
Stop paying for overpriced round-trip latency
Why route queries over Western servers when you can use low-overhead hardware located in Nairobi? Save 87% on your monthly inference spend. No minimum credit limits. M-Pesa ready.