ResoClient

Struct ResoClient 

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

RESO Web API client

Implementations§

Source§

impl ResoClient

Source

pub fn from_env() -> Result<Self>

Create a new client from environment variables

§Environment Variables
  • RESO_BASE_URL - Base URL of the RESO server (required) Example: https://api.mls.com/api/v2/OData
  • RESO_TOKEN - OAuth bearer token (required)
  • RESO_DATASET_ID - Dataset ID for URL path (optional)
  • RESO_TIMEOUT - Timeout in seconds (optional, default: 30)
§Examples
let client = ResoClient::from_env()?;
Source

pub fn with_config(config: ClientConfig) -> Result<Self>

Create a new client with manual configuration

§Examples
let config = ClientConfig::new(
    "https://api.mls.com/reso/odata",
    "your-token"
);
let client = ResoClient::with_config(config)?;
Source

pub fn base_url(&self) -> &str

Get the base URL

§Examples
let config = ClientConfig::new("https://api.mls.com/odata", "token");
let client = ResoClient::with_config(config)?;
assert_eq!(client.base_url(), "https://api.mls.com/odata");
Source

pub async fn execute(&self, query: &Query) -> Result<Value>

Execute a query and return raw JSON

Executes a standard OData query and returns the full JSON response. The response follows the OData format with records in a value array.

§Examples
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin'")
    .select(&["ListingKey", "City", "ListPrice"])
    .top(10)
    .build()?;

let results = client.execute(&query).await?;

// Access records from OData response
if let Some(records) = results["value"].as_array() {
    for record in records {
        println!("{}", record["ListingKey"]);
    }
}

// Access count if requested with with_count()
if let Some(count) = results["@odata.count"].as_u64() {
    println!("Total: {}", count);
}
Source

pub async fn execute_by_key(&self, query: &Query) -> Result<Value>

Execute a direct key access query and return a single record

Direct key access queries (e.g., Property('12345')) return a single object instead of an array wrapped in {"value": [...]}. This method is optimized for such queries.

§Examples
// Fetch a single property by key
let query = QueryBuilder::by_key("Property", "12345")
    .select(&["ListingKey", "City", "ListPrice"])
    .build()?;

let record = client.execute_by_key(&query).await?;

// With expand
let query = QueryBuilder::by_key("Property", "12345")
    .expand(&["ListOffice", "ListAgent"])
    .build()?;

let record = client.execute_by_key(&query).await?;
Source

pub async fn execute_count(&self, query: &Query) -> Result<u64>

Execute a count-only query and return the count as an integer

Uses the OData /$count endpoint to efficiently get just the count without fetching any records. More efficient than using with_count() when you only need the count.

§Examples
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin'")
    .count()
    .build()?;

let count = client.execute_count(&query).await?;
println!("Total properties in Austin: {}", count);
Source

pub async fn fetch_metadata(&self) -> Result<String>

Fetch $metadata XML

Retrieves the OData metadata document which describes the schema, entity types, properties, and relationships available in the API.

§Examples
let metadata = client.fetch_metadata().await?;

// Parse or save the XML metadata
println!("Metadata length: {} bytes", metadata.len());
Source

pub async fn execute_replication( &self, query: &ReplicationQuery, ) -> Result<ReplicationResponse>

Execute a replication query

The replication endpoint is designed for bulk data transfer and supports up to 2000 records per request. The response includes a next link in the headers for pagination through large datasets.

§Important Notes
  • Replication functionality requires MLS authorization
  • Results are ordered oldest to newest by default
  • Use $select to reduce payload size and improve performance
  • For datasets >10,000 records, replication is required
§Examples
let query = ReplicationQueryBuilder::new("Property")
    .filter("StandardStatus eq 'Active'")
    .select(&["ListingKey", "City", "ListPrice"])
    .top(2000)
    .build()?;

let response = client.execute_replication(&query).await?;

println!("Retrieved {} records", response.record_count);

// Continue with next link if more records available
if let Some(next_link) = response.next_link {
    let next_response = client.execute_next_link(&next_link).await?;
}

Execute a next link from a previous replication response

Takes the full URL from a previous replication response’s next_link field and fetches the next batch of records.

§Examples
let query = ReplicationQueryBuilder::new("Property")
    .top(2000)
    .build()?;

let mut response = client.execute_replication(&query).await?;
let mut total_records = response.record_count;

// Continue fetching while next link is available
while let Some(next_link) = response.next_link {
    response = client.execute_next_link(&next_link).await?;
    total_records += response.record_count;
}

println!("Total records fetched: {}", total_records);

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> 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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: 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: 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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