Skip to main content

Module rest

Module rest 

Source
Expand description

REST API client module for OpenAI interface

This module provides the core HTTP functionality for making requests to OpenAI-compatible APIs. It includes traits and implementations for both streaming and non-streaming API calls.

§Overview

The rest module contains:

  • post: HTTP POST request functionality with streaming and non-streaming support
  • get: HTTP GET request functionality with various parameter handling options
  • delete: HTTP DELETE request functionality
  • options: Per-request authentication (RequestOptions, Auth) taken by every request method
  • default_client: A reqwest::Client constructor shared by all request traits
  • check_status: Shared non-2xx response handling which parses the error body
  • skip_deserialization_errors: A stream adapter that drops chunks which fail to deserialize

§Usage

The module is designed to be used through the higher-level API modules (chat, completions, etc.). However, you can use the traits directly if needed:

§POST Requests

use openai_interface::rest::{post::{Post, PostNoStream}, RequestOptions};
use openai_interface::errors::OapiError;
use serde::{Serialize, Deserialize};

use std::str::FromStr;

#[derive(Serialize)]
struct MyRequest {
    prompt: String,
    stream: bool,
}

#[derive(Deserialize)]
struct MyResponse {
    // Define the fields of your response here
    id: String,
}

impl FromStr for MyResponse {
    type Err = OapiError;

    fn from_str(content: &str) -> Result<Self, Self::Err> {
        let parse_result: Result<Self, _> = serde_json::from_str(content)
            .map_err(|e| OapiError::DeserializationError(e.to_string()));
        parse_result
    }
}

impl Post for MyRequest {
    fn is_streaming(&self) -> bool {
        self.stream
    }
    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
        Ok(format!("{}/service", base_url))
    }
}

impl PostNoStream for MyRequest {
    type Response = MyResponse;
}

// Send it with a client:
// let client = openai_interface::rest::default_client();
// let response: MyResponse = request
//     .get_response(&client, "https://api.openai.com/v1/chat/completions", &RequestOptions::bearer("API_KEY"))
//     .await?;

§GET Requests

use openai_interface::rest::get::Get;
use openai_interface::errors::OapiError;

// GET request with URL building
struct ComplexRequest {
    resource_id: String,
    limit: Option<u32>,
}

impl Get for ComplexRequest {
    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
        let mut url = format!("{}/{}", base_url, self.resource_id);
        if let Some(limit) = self.limit {
            url.push_str(&format!("?limit={}", limit));
        }
        Ok(url)
    }
}

§Client configuration

Every request method takes the client as its first argument, so callers control proxies, timeouts and connection pooling. Use default_client for a sensible default, or build your own, e.g. with a proxy:

// Building a client needs an installed provider: this one comes from the
// `ferritls` feature (see "TLS crypto provider" below).
openai_interface::rest::install_crypto_provider().ok();
let client = reqwest::Client::builder()
    .proxy(reqwest::Proxy::http("http://127.0.0.1:10808")?)
    .timeout(std::time::Duration::from_secs(60))
    .build()?;

§TLS crypto provider

This crate depends on reqwest with its rustls-no-provider feature, so the rustls stack is compiled without a crypto backend. That leaves the choice of backend to the application: exactly one rustls::crypto::CryptoProvider must be installed as the process default before any reqwest::Client is built, otherwise reqwest panics at construction time.

Nothing in this crate installs a provider for you — neither default_client nor any request method touches the global state, so an application that picked a provider first keeps it, and an application that never builds a client through this crate is free to install its own whenever it likes.

This example is the regression lock for that promise. It runs as should_panic, deliberately with no provider installed and no hidden ferritls setup: if default_client() ever learns to install one on the side, it stops panicking and cargo test fails.

ⓘ
let _client = openai_interface::rest::default_client();

§With the ferritls feature

The optional ferritls feature (off by default) adds the pure-Rust ferritls-rustls backend and the install_crypto_provider helper. Enable it when you are happy to let this crate pick a provider for you:

[dependencies]
openai-interface = { version = "0.10", features = ["ferritls"] }

Then call it once at startup, before the first client:

openai_interface::rest::install_crypto_provider()
    .expect("a rustls crypto provider was already installed");
let client = openai_interface::rest::default_client();

§Without it

With the feature off, ferritls-rustls is not in the dependency tree at all and install_crypto_provider does not exist. Install a provider yourself instead — first install wins, so do it before any client is built:

ⓘ
// In the application crate, with `rustls = "0.23"` (feature `ring` or
// `aws-lc-rs`) as one of its own dependencies:
rustls::crypto::ring::default_provider()
    .install_default()
    .expect("a rustls crypto provider was already installed");

§When reqwest already has a backend

Because Cargo features are additive, a project that depends on reqwest itself with default-tls / rustls (its defaults, which fall back to the bundled aws-lc-rs provider) or with native-tls (which skips the rustls path entirely) needs no provider installed here at all. That backend is then picked by feature unification instead of by you; see the “TLS Crypto Provider” section of the crate docs for the trade-off.

Re-exports§

pub use options::Auth;
pub use options::RequestOptions;

Modules§

delete
Delete request
get
GET request functionality for OpenAI interface
options
Per-request authentication and header options.
post

Functions§

check_status
Checks a response status, turning a non-2xx response into an OapiError::ApiError that carries the parsed error body.
default_client
Builds a reqwest::Client with library defaults.
install_crypto_provider
Installs the pure-Rust ferritls-rustls crypto provider as the process-wide default for rustls.
skip_deserialization_errors
Drops the items of a parsed stream that failed to deserialize.