Skip to main content

ProductService API Reference

ProductService is a shared singleton service that provides a centralized way to load products across all SDK components. It eliminates code duplication and provides consistent error handling.

Overview

The ProductService class:

  • Eliminates duplication - All components use the same service
  • Caches SDK client - Improves performance by reusing connections
  • Consistent error handling - Standardized error types across components
  • Thread-safe - Safe to use from any thread with @MainActor

Import

import ReachuUI

Singleton Access

let productService = ProductService.shared

Methods

Load Single Product

Load a single product by ID (as String or Int).

// Using String ID
let product = try await ProductService.shared.loadProduct(
productId: "123",
currency: "USD",
country: "US"
)

// Using Int ID
let product = try await ProductService.shared.loadProduct(
productId: 123,
currency: "USD",
country: "US"
)

Parameters: - productId: Product ID (String or Int)

  • currency: Currency code (e.g., "USD", "EUR")
  • country: Country code for shipping (e.g., "US", "DE")

Returns:Product if found

Throws:ProductServiceError for various error conditions

Load Multiple Products

Load multiple products by IDs, or all products if IDs are empty/nil.

// Load specific products
let products = try await ProductService.shared.loadProducts(
productIds: [123, 456, 789],
currency: "USD",
country: "US"
)

// Load all products (pass nil or empty array)
let allProducts = try await ProductService.shared.loadProducts(
productIds: nil,
currency: "USD",
country: "US"
)

Parameters: - productIds: Array of product IDs (Int). If nil or empty, loads all products from channel

  • currency: Currency code (e.g., "USD", "EUR")
  • country: Country code for shipping (e.g., "US", "DE")

**Returns:**Array of Product objects

Throws:ProductServiceError for various error conditions

Clear Cache

Clear the cached SDK client (useful for testing or reconfiguration).

ProductService.shared.clearCache()

Error Handling

ProductService throws ProductServiceError enum with the following cases:

public enum ProductServiceError: LocalizedError {
case invalidConfiguration(String)
case invalidProductId(String)
case productNotFound(Int)
case sdkError(SdkException)
case networkError(Error)
}

Example Error Handling

do {
let product = try await ProductService.shared.loadProduct(
productId: "123",
currency: "USD",
country: "US"
)
// Use product
} catch ProductServiceError.invalidProductId(let id) {
print("Invalid product ID: \(id)")
} catch ProductServiceError.productNotFound(let id) {
print("Product not found: \(id)")
} catch ProductServiceError.invalidConfiguration(let message) {
print("Configuration error: \(message)")
} catch ProductServiceError.sdkError(let error) {
print("SDK error: \(error.message ?? "Unknown")")
} catch ProductServiceError.networkError(let error) {
print("Network error: \(error.localizedDescription)")
} catch {
print("Unexpected error: \(error)")
}

Usage Examples

Basic Usage

import SwiftUI
import ReachuUI

struct ProductDetailView: View {
@State private var product: Product?
@State private var isLoading = false
@State private var errorMessage: String?

let productId: String

var body: some View {
Group {
if isLoading {
ProgressView()
} else if let product = product {
ProductView(product: product)
} else if let error = errorMessage {
Text("Error: \(error)")
}
}
.task {
await loadProduct()
}
}

@MainActor
private func loadProduct() async {
isLoading = true
errorMessage = nil

do {
product = try await ProductService.shared.loadProduct(
productId: productId,
currency: "USD",
country: "US"
)
} catch ProductServiceError.productNotFound(let id) {
errorMessage = "Product \(id) not found"
} catch {
errorMessage = error.localizedDescription
}

isLoading = false
}
}

Loading Multiple Products

import SwiftUI
import ReachuUI

struct ProductListView: View {
@State private var products: [Product] = []
@State private var isLoading = false

let productIds: [Int]

var body: some View {
List(products) { product in
ProductRow(product: product)
}
.task {
await loadProducts()
}
}

@MainActor
private func loadProducts() async {
isLoading = true

do {
products = try await ProductService.shared.loadProducts(
productIds: productIds,
currency: "USD",
country: "US"
)
} catch {
print("Failed to load products: \(error)")
}

isLoading = false
}
}

Loading All Products

@MainActor
private func loadAllProducts() async {
do {
// Pass nil or empty array to load all products
let allProducts = try await ProductService.shared.loadProducts(
productIds: nil,
currency: "USD",
country: "US"
)

print("Loaded \(allProducts.count) products")
} catch {
print("Error: \(error)")
}
}

Integration with Components

All SDK components (RProductBanner, RProductCarousel, RProductStore, RProductSpotlight) use ProductService internally. You don't need to use it directly unless you're building custom components.

Custom Component Example

import SwiftUI
import ReachuUI

struct CustomProductView: View {
@State private var products: [Product] = []

var body: some View {
ScrollView {
LazyVStack {
ForEach(products) { product in
ProductCard(product: product)
}
}
}
.task {
await loadProducts()
}
}

@MainActor
private func loadProducts() async {
do {
products = try await ProductService.shared.loadProducts(
productIds: nil, // Load all products
currency: "USD",
country: "US"
)
} catch {
print("Failed to load: \(error)")
}
}
}

Performance Considerations

  • SDK Client Caching: The service caches the SdkClient instance to avoid recreating it on every call
  • Thread Safety: All methods are marked with @MainActor for safe UI updates
  • Error Handling: Errors are properly typed and localized for better debugging

Best Practices

  1. Always handle errors: Use do-catch blocks when calling ProductService methods
  2. Use appropriate currency/country: Pass the correct values from your app's configuration
  3. Clear cache when needed: Call clearCache() if you reconfigure the SDK
  4. Use async/await: All methods are async and should be called with await