SimpleLLMDocs
Integrations
Markdown ↗

Go and Rust

HTTP examples using standard Go and Rust reqwest.

Any HTTP client can call SimpleLLM. These complete examples avoid coupling your application to a third-party OpenAI SDK version and use the same JSON request as cURL.

Set SIMPLELLM_API_KEY and SIMPLELLM_MODEL first, as shown in the Quickstart. Both examples make one non-streaming request with an application-selected ten-minute deadline.

Go

Save this as main.go and run go run main.go. It uses only the standard library, checks HTTP status, handles a missing choice, and propagates Ctrl+C through the request context.

go
package main

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "os/signal"
    "time"
)

func run() error {
    key, model := os.Getenv("SIMPLELLM_API_KEY"), os.Getenv("SIMPLELLM_MODEL")
    if key == "" || model == "" {
        return fmt.Errorf("set SIMPLELLM_API_KEY and SIMPLELLM_MODEL")
    }
    ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
    defer cancel()
    payload, err := json.Marshal(map[string]any{
        "model": model,
        "messages": []map[string]string{
            {"role": "user", "content": "Explain a hash table briefly."},
        },
        "max_tokens": 2048,
    })
    if err != nil { return err }
    req, err := http.NewRequestWithContext(ctx, http.MethodPost,
        "https://api.simplellm.eu/v1/chat/completions", bytes.NewReader(payload))
    if err != nil { return err }
    req.Header.Set("Authorization", "Bearer "+key)
    req.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 10 * time.Minute}
    resp, err := client.Do(req)
    if err != nil { return err }
    defer resp.Body.Close()
    body, err := io.ReadAll(io.LimitReader(resp.Body, 8<<20))
    if err != nil { return err }
    if resp.StatusCode != http.StatusOK {
        return fmt.Errorf("inference HTTP %d", resp.StatusCode)
    }
    var result struct {
        Choices []struct {
            Message struct { Content *string }
        }
        Usage json.RawMessage
    }
    if err := json.Unmarshal(body, &result); err != nil { return err }
    if len(result.Choices) == 0 { return fmt.Errorf("response has no choices") }
    if text := result.Choices[0].Message.Content; text != nil { fmt.Println(*text) }
    fmt.Println("Usage:", string(result.Usage))
    return nil
}

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

Rust

Create a binary project and add the dependencies:

bash
cargo new simplellm-example
cd simplellm-example
cargo add reqwest --features json
cargo add tokio --features macros,rt-multi-thread,signal
cargo add serde_json

Replace src/main.rs with this example, then run cargo run.

rust
use serde_json::{json, Value};
use std::{env, error::Error, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let key = env::var("SIMPLELLM_API_KEY")?;
    let model = env::var("SIMPLELLM_MODEL")?;
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(600))
        .build()?;
    let request = client
        .post("https://api.simplellm.eu/v1/chat/completions")
        .bearer_auth(key)
        .json(&json!({
            "model": model,
            "messages": [{"role": "user", "content": "Explain a hash table briefly."}],
            "max_tokens": 2048
        }));
    let work = async {
        let response = request.send().await?.error_for_status()?;
        response.json::<Value>().await
    };
    let result = tokio::select! {
        result = work => result?,
        signal = tokio::signal::ctrl_c() => {
            signal?;
            eprintln!("Cancelled");
            return Ok(());
        }
    };
    let choice = result["choices"].get(0).ok_or("response has no choices")?;
    println!("{}", choice["message"]["content"].as_str().unwrap_or(""));
    println!("Usage: {}", result["usage"]);
    Ok(())
}

Dropping the pending HTTP work on Ctrl+C cancels the client operation; already performed inference can still incur a charge.

Adding streaming

For Go, consume the response body incrementally; for Rust, use the HTTP client's incremental body interface. A network read is not an SSE event and not a token.

If implementing your own parser, buffer incomplete lines, handle blank-line event boundaries, join data lines, and recognize [DONE]. Go's default Scanner token limit can be too small for large events, so choose an explicit bounded buffer or a reader-based parser.

See Streaming for the wire format, usage-only events, and interruption behavior.

Search the complete documentation.