Skip to main content

ProviderLayer

Struct ProviderLayer 

Source
pub struct ProviderLayer { /* private fields */ }
Expand description

A tower layer that sends requests to a provider: another host (and path prefix) serving the same API, with its own headers, query parameters and paths.

A request is the provider’s when its URL starts with the provider’s base URL, or with the base declared with ProviderLayer::rewrite_from, which is then replaced with the provider’s: same scheme, host and port, and a path that starts with the base’s path at a segment boundary (/v1 holds /v1 and /v1/models, not /v10). To such a request the layer, in this order:

  1. replaces the base (scheme, host, port and path prefix) with the provider’s, keeping the rest of the path and the query;
  2. rewrites the rest of the path with ProviderLayer::map_path, if set;
  3. sets the headers, each replacing every value the request has under its name;
  4. sets the query parameters, each replacing the parameters of its name the request has.

Any other request (a download from another host, say) is passed on unchanged, so the provider’s credentials are never sent elsewhere.

There are two ways to point a generated client at a provider:

  • Set Configuration.base_path to the provider’s base URL and add ProviderLayer::new(provider_base) for the headers, query parameters and paths. The requests already start with the provider’s base.
  • Keep the generated base_path and declare it with .rewrite_from(generated_base): the layer moves every request under it to the provider. This suits a Client shared by several Configurations, or a crate that hands out a ready-made client for a provider.
use timvw_rust_runtime::provider::ProviderLayer;

// An OpenAI-compatible provider under another base URL, with headers of its own.
let openrouter_like = ProviderLayer::new("https://openrouter.example/api/v1")?
    .rewrite_from("https://api.openai.com/v1")?
    .sensitive_header("authorization", "Bearer sk-or-123")?
    .header("x-title", "my app")?;

assert_eq!(
    openrouter_like.rewrite_uri(&"https://api.openai.com/v1/models?limit=2".parse()?)?.to_string(),
    "https://openrouter.example/api/v1/models?limit=2"
);

// A provider that puts a deployment in the path and wants an `api-version` on every request.
let azure_like = ProviderLayer::new("https://my-resource.example.com/openai")?
    .rewrite_from("https://api.openai.com/v1")?
    .sensitive_header("api-key", "secret")?
    .query(&[("api-version", "2024-10-21")])?
    .map_path(|path| format!("/deployments/my-deployment{path}"));

assert_eq!(
    azure_like.rewrite_uri(&"https://api.openai.com/v1/chat/completions".parse()?)?.to_string(),
    "https://my-resource.example.com/openai/deployments/my-deployment/chat/completions?api-version=2024-10-21"
);

Add it with Client::layer, to Client::default() or to a generated Configuration.client. Added last, it sees each request first and rewrites it once, before the retries.

Implementations§

Source§

impl ProviderLayer

Source

pub fn new(base_url: &str) -> Result<Self, Error>

A provider whose API is at base_url, such as https://openrouter.ai/api/v1. Fails, with an error whose is_builder() is true, on a URL that is not absolute or that has a query or fragment.

Source

pub fn rewrite_from(self, base_url: &str) -> Result<Self, Error>

Moves the requests under base_url, typically a generated client’s default base_path such as https://api.openai.com/v1, to the provider: base_url is replaced with the provider’s base URL, and the rest of the path and the query are kept. Fails like ProviderLayer::new. Calling it again replaces the base.

Source

pub fn header<K, V>(self, name: K, value: V) -> Result<Self, Error>

Sets a header on every request to the provider, replacing every value the request has under that name (the generated client’s included). Calling it again for the same name replaces the value. Fails, with an error whose is_builder() is true, on an invalid name or value.

Source

pub fn sensitive_header<K, V>(self, name: K, value: V) -> Result<Self, Error>

Like ProviderLayer::header, and marks the value sensitive (see HeaderValue::set_sensitive): for an API key, so that it is left out of Debug output.

Source

pub fn headers(self, headers: HeaderMap) -> Self

Sets every header of a map, replacing the values set before under its names. A name with several values keeps them all. Values marked sensitive stay sensitive.

Source

pub fn query<T: Serialize + ?Sized>(self, query: &T) -> Result<Self, Error>

Sets query parameters on every request to the provider, such as api-version, serialized as application/x-www-form-urlencoded: a sequence of pairs, a map or a struct. Each replaces the parameters of its name the request has; a name given twice here is sent twice. Fails, with an error whose is_builder() is true, on a value that is not a flat list of pairs.

Source

pub fn map_path<F>(self, f: F) -> Self
where F: Fn(&str) -> String + Send + Sync + 'static,

Rewrites the path of each request to the provider, relative to the base URL: f gets the path after the base (/chat/completions for https://api.openai.com/v1/chat/completions with base https://api.openai.com/v1; empty for the base itself), percent-encoded, and returns the new one, which is put after the provider’s base.

Source

pub fn base_url(&self) -> &str

The provider’s base URL.

Source

pub fn header_map(&self) -> &HeaderMap

The headers set on each request to the provider.

Source

pub fn query_pairs(&self) -> &[(String, String)]

The query parameters set on each request to the provider, decoded, in order.

Source

pub fn rewrite_uri(&self, uri: &Uri) -> Result<Uri, Error>

The URL a request to uri is sent to: moved to the provider, its path rewritten and its query parameters set, or uri unchanged when it is not the provider’s. Fails, with an error whose is_builder() is true, when the rewritten URL is invalid.

Trait Implementations§

Source§

impl Clone for ProviderLayer

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ProviderLayer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S> Layer<S> for ProviderLayer

Source§

type Service = Provider<S>

The wrapped service
Source§

fn layer(&self, inner: S) -> Self::Service

Wrap the given service with the middleware, returning a new service that has been decorated with the middleware.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> MaybeSync for T
where T: Sync + ?Sized,

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more