littleshop/LittleShop.Client/README.md
sysadmin 1f7c0af497 Add LittleShop.Client SDK library with complete API wrapper
Features:
- Complete .NET client SDK for LittleShop API
- JWT authentication with automatic token management
- Catalog service for products and categories
- Order service with payment creation
- Retry policies using Polly for resilience
- Error handling middleware
- Dependency injection support
- Comprehensive documentation and examples

SDK Components:
- Authentication service with token refresh
- Strongly-typed models for all API responses
- HTTP handlers for retry and error handling
- Extension methods for easy DI registration
- Example console application demonstrating usage

Test Updates:
- Fixed test compilation errors
- Updated test data builders for new models
- Corrected service constructor dependencies
- Fixed enum value changes (PaymentStatus, OrderStatus)

Documentation:
- Complete project README with features and usage
- Client SDK README with detailed examples
- API endpoint documentation
- Security considerations
- Deployment guidelines

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-20 18:15:35 +01:00

9.8 KiB

LittleShop Client SDK

A .NET client library for interacting with the LittleShop e-commerce API. This SDK provides a strongly-typed, easy-to-use interface for all LittleShop API endpoints with built-in authentication, retry policies, and error handling.

Installation

Add the LittleShop.Client library to your project:

dotnet add reference ../LittleShop.Client/LittleShop.Client.csproj

Or via NuGet (when published):

dotnet add package LittleShop.Client

Quick Start

Basic Setup with Dependency Injection

using LittleShop.Client.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        // Add LittleShop client with configuration
        services.AddLittleShopClient(options =>
        {
            options.BaseUrl = "https://localhost:5001";
            options.TimeoutSeconds = 30;
            options.MaxRetryAttempts = 3;
            options.EnableLogging = true;
        });
    })
    .Build();

// Get the client from DI
var client = host.Services.GetRequiredService<ILittleShopClient>();

Simple Console Application Example

using LittleShop.Client;
using LittleShop.Client.Extensions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

// Setup DI container
var services = new ServiceCollection();
services.AddLogging(builder => builder.AddConsole());
services.AddLittleShopClient("https://localhost:5001");

var serviceProvider = services.BuildServiceProvider();
var client = serviceProvider.GetRequiredService<ILittleShopClient>();

// Authenticate
var loginResult = await client.Authentication.LoginAsync("admin", "admin");
if (loginResult.IsSuccess)
{
    Console.WriteLine($"Logged in as: {loginResult.Data.Username}");
    Console.WriteLine($"Token expires: {loginResult.Data.ExpiresAt}");
}

// Get categories
var categoriesResult = await client.Catalog.GetCategoriesAsync();
if (categoriesResult.IsSuccess)
{
    foreach (var category in categoriesResult.Data)
    {
        Console.WriteLine($"Category: {category.Name} - {category.Description}");
    }
}

// Get products with filtering
var productsResult = await client.Catalog.GetProductsAsync(
    pageNumber: 1,
    pageSize: 10,
    searchTerm: "wireless",
    minPrice: 10,
    maxPrice: 100
);

if (productsResult.IsSuccess)
{
    Console.WriteLine($"Found {productsResult.Data.TotalCount} products");
    foreach (var product in productsResult.Data.Items)
    {
        Console.WriteLine($"Product: {product.Name} - £{product.Price}");
    }
}

Authentication

The SDK handles JWT authentication automatically. Once you log in, the token is stored and automatically included in subsequent requests.

// Login
var loginResult = await client.Authentication.LoginAsync("username", "password");
if (!loginResult.IsSuccess)
{
    Console.WriteLine($"Login failed: {loginResult.ErrorMessage}");
    return;
}

// Check if authenticated
if (client.Authentication.IsAuthenticated())
{
    Console.WriteLine("User is authenticated");
}

// Get current token (if needed for external use)
var token = client.Authentication.GetToken();

// Logout
client.Authentication.Logout();

Catalog Operations

Get All Categories

var result = await client.Catalog.GetCategoriesAsync();
if (result.IsSuccess)
{
    foreach (var category in result.Data)
    {
        Console.WriteLine($"{category.Name}: {category.Description}");
    }
}

Get Products with Pagination and Filtering

var result = await client.Catalog.GetProductsAsync(
    pageNumber: 1,
    pageSize: 20,
    categoryId: categoryGuid,     // Optional: Filter by category
    searchTerm: "headphones",      // Optional: Search term
    minPrice: 50,                  // Optional: Minimum price
    maxPrice: 200                  // Optional: Maximum price
);

if (result.IsSuccess)
{
    Console.WriteLine($"Page {result.Data.PageNumber} of {result.Data.TotalPages}");
    Console.WriteLine($"Total products: {result.Data.TotalCount}");
    
    foreach (var product in result.Data.Items)
    {
        Console.WriteLine($"{product.Name} - £{product.Price}");
        if (product.Photos.Any())
        {
            Console.WriteLine($"  Photo: {product.Photos.First().Url}");
        }
    }
}

Get Single Product

var result = await client.Catalog.GetProductByIdAsync(productId);
if (result.IsSuccess)
{
    var product = result.Data;
    Console.WriteLine($"Name: {product.Name}");
    Console.WriteLine($"Price: £{product.Price}");
    Console.WriteLine($"Weight: {product.Weight} {product.WeightUnit}");
}

Order Operations

Create Order

var orderRequest = new CreateOrderRequest
{
    IdentityReference = "CUST123",
    ShippingName = "John Smith",
    ShippingAddress = "123 Main Street",
    ShippingCity = "London",
    ShippingPostCode = "SW1A 1AA",
    ShippingCountry = "United Kingdom",
    Notes = "Please deliver to reception",
    Items = new List<CreateOrderItem>
    {
        new CreateOrderItem 
        { 
            ProductId = productId1, 
            Quantity = 2 
        },
        new CreateOrderItem 
        { 
            ProductId = productId2, 
            Quantity = 1 
        }
    }
};

var result = await client.Orders.CreateOrderAsync(orderRequest);
if (result.IsSuccess)
{
    Console.WriteLine($"Order created: {result.Data.Id}");
    Console.WriteLine($"Total: £{result.Data.TotalAmount}");
}

Get Orders by Customer Identity

var result = await client.Orders.GetOrdersByIdentityAsync("CUST123");
if (result.IsSuccess)
{
    foreach (var order in result.Data)
    {
        Console.WriteLine($"Order {order.Id}: {order.Status} - £{order.TotalAmount}");
        Console.WriteLine($"  Created: {order.CreatedAt}");
        if (!string.IsNullOrEmpty(order.TrackingNumber))
        {
            Console.WriteLine($"  Tracking: {order.TrackingNumber}");
        }
    }
}

Create Cryptocurrency Payment

var result = await client.Orders.CreatePaymentAsync(orderId, "BTC");
if (result.IsSuccess)
{
    var payment = result.Data;
    Console.WriteLine($"Payment ID: {payment.Id}");
    Console.WriteLine($"Send {payment.RequiredAmount} {payment.Currency} to:");
    Console.WriteLine($"Address: {payment.WalletAddress}");
    Console.WriteLine($"Expires: {payment.ExpiresAt}");
    
    if (!string.IsNullOrEmpty(payment.BTCPayCheckoutUrl))
    {
        Console.WriteLine($"Or pay via: {payment.BTCPayCheckoutUrl}");
    }
}

Error Handling

All API methods return an ApiResponse<T> wrapper that includes success status, data, and error information:

var result = await client.Catalog.GetProductByIdAsync(productId);

if (result.IsSuccess)
{
    // Success - access data
    var product = result.Data;
    Console.WriteLine($"Product: {product.Name}");
}
else
{
    // Error - handle appropriately
    Console.WriteLine($"Error: {result.ErrorMessage}");
    Console.WriteLine($"Status Code: {result.StatusCode}");
    
    switch (result.StatusCode)
    {
        case HttpStatusCode.NotFound:
            Console.WriteLine("Product not found");
            break;
        case HttpStatusCode.Unauthorized:
            Console.WriteLine("Please login first");
            break;
        case HttpStatusCode.BadRequest:
            Console.WriteLine("Invalid request");
            break;
        default:
            Console.WriteLine("An error occurred");
            break;
    }
}

Advanced Configuration

Custom HTTP Client Configuration

The SDK uses Polly for retry policies and includes automatic retry for transient failures:

services.AddLittleShopClient(options =>
{
    options.BaseUrl = "https://api.littleshop.com";
    options.TimeoutSeconds = 60;        // Request timeout
    options.MaxRetryAttempts = 5;       // Number of retries for transient failures
    options.EnableLogging = true;       // Enable detailed logging
});

Using in ASP.NET Core Web Application

// In Program.cs or Startup.cs
builder.Services.AddLittleShopClient(options =>
{
    options.BaseUrl = builder.Configuration["LittleShop:ApiUrl"];
    options.TimeoutSeconds = 30;
});

// In a controller or service
public class ProductController : Controller
{
    private readonly ILittleShopClient _client;
    
    public ProductController(ILittleShopClient client)
    {
        _client = client;
    }
    
    public async Task<IActionResult> Index()
    {
        var result = await _client.Catalog.GetProductsAsync();
        if (result.IsSuccess)
        {
            return View(result.Data.Items);
        }
        
        return View("Error", result.ErrorMessage);
    }
}

Features

  • Strongly Typed Models - All API responses are mapped to C# classes
  • Automatic Authentication - JWT tokens are managed automatically
  • Retry Policies - Automatic retry for transient failures
  • Error Handling - Consistent error responses with detailed information
  • Logging Support - Built-in logging for debugging
  • Dependency Injection - Full DI support for ASP.NET Core applications
  • Async/Await - All methods are async for better performance
  • Pagination Support - Built-in pagination for product listings
  • Filtering & Search - Advanced filtering options for products

API Coverage

  • Authentication

    • Login
    • Token refresh
    • Logout
  • Catalog

    • Get all categories
    • Get category by ID
    • Get products (with pagination and filtering)
    • Get product by ID
  • Orders

    • Create order
    • Get orders by customer identity
    • Get order by ID
    • Create cryptocurrency payment
    • Get order payments

Requirements

  • .NET 9.0 or later
  • LittleShop API server running and accessible

License

This SDK is part of the LittleShop e-commerce platform.