supplier_kit 0.1.1

A modular toolkit for managing and grouping dynamic data suppliers.
Documentation
# supplier_kit

**A modular toolkit for managing and grouping dynamic data suppliers.**

`supplier_kit` helps you build robust and extensible architectures that rely
on multiple external or internal data providers — known as *suppliers*. It is ideal
for use cases such as federated API calls, service orchestration, or data aggregation
(e.g., e-commerce platforms).

---

## ✨ Features

- `Supplier` trait: defines a common interface for all data providers
- `SupplierRegistry`: a container for registering and accessing suppliers by name
- `SupplierGroup`: abstraction to query multiple suppliers in a batch
- `SupplierGroupResult`: returns per-supplier successes and failures
- `register_suppliers!` macro: for easy supplier registration
- Utility helpers like `add_supplier_from_registry` and `add_suppliers_from_registry` as an option

---

## 🔧  Use Cases

- Aggregating product listings from multiple platforms
- Wrapping multiple internal microservices behind unified access
- Resilient systems that gracefully handle partial failure

---

## 🚀  Quick Start

### Example: Registering and Querying Multiple Suppliers

This example demonstrates how to use `SupplierRegistry` and `BasicSupplierGroup`
to register multiple suppliers, group them, and execute a `Search` operation.

It includes:
- Using the `register_suppliers!` macro
- Handling partial failures using `add_suppliers_from_registry`
- Group querying with `SupplierGroup` trait

```rust
use supplier_kit::models::{SupplierRequest, SupplierResponse, SupplierOperation};
use supplier_kit::supplier::{Supplier, SupplierRegistry};
use supplier_kit::supplier_group::{SupplierGroup, BasicSupplierGroup, SupplierGroupResult};
use supplier_kit::errors::SupplierError;
use supplier_kit::register_suppliers;
use serde_json::json;
use supplier_kit::utils::add_suppliers_from_registry;

struct MockSupplier {
    name: String,
    should_fail: bool,
}

impl MockSupplier {
    fn new(name: &str, should_fail: bool) -> Self {
        Self {
            name: name.to_string(),
            should_fail,
        }
    }
}

impl Supplier for MockSupplier {
    fn name(&self) -> &str {
        &self.name
    }

    fn query(&self, request: SupplierRequest) -> Result<SupplierResponse, SupplierError> {
        if self.should_fail {
            Err(SupplierError::Internal(format!("{} failed", self.name)))
        } else {
            Ok(SupplierResponse {
                data: json!({
                    "supplier": self.name,
                    "params": request.params
                }),
            })
        }
    }
}

fn main() -> Result<(), SupplierError> {
    let mut registry = SupplierRegistry::new();
    register_suppliers!(
        registry,
        "s1" => MockSupplier::new("s1", false),
        "s2" => MockSupplier::new("s2", true),
        "s3" => MockSupplier::new("s3", false),
    );

    let mut group = BasicSupplierGroup::new("example_group");

    let failures = add_suppliers_from_registry(&mut group, &registry, &["s1", "s2", "s4"]);

    if !failures.is_empty() {
        for (name, err) in failures {
            println!("Failed to add '{}': {}", name, err);
        }
    }

    let request = SupplierRequest {
        operation: SupplierOperation::Search,
        params: json!({ "keyword": "laptop" }),
    };

    let result: SupplierGroupResult = group.query(request);

    println!("Successes:");
    for (name, response) in result.successes {
        println!("- [{}] Response: {}", name, response.data);
    }

    println!("Failures:");
    for (name, error) in result.failures {
        println!("- [{}] Error: {}", name, error);
    }

    Ok(())
}
```

---

## 📄 License

Licensed under the [Apache-2.0 license](http://www.apache.org/licenses/LICENSE-2.0.txt)

---

## 👨 Author

Jerry Maheswara <jerrymaheswara@gmail.com>

---

## ❤️ Built with Love in Rust

This project is built with ❤️ using **Rust** — a systems programming language that is safe, fast, and concurrent.  
Rust is the perfect choice for building reliable and efficient applications.

---

## 🤝 Contributing

Pull requests, issues, and feedback are welcome!  
If you find this crate useful, give it a ⭐ and share it with others in the Rustacean community.

---