Source of truth (2026)
  • Core partial files in DataManagementEngineStandard/WebAPI/:
    • WebAPIDataSource.cs — properties, constructor, helper wiring, dispose
    • WebAPIDataSource.Connection.cs — Openconnection / Closeconnection / transactions
    • WebAPIDataSource.Http.cs — GetAsync, PostAsync, PutAsync, DeleteAsync convenience methods
    • WebAPIDataSource.Data.cs — CRUD: GetEntity, InsertEntity, UpdateEntity, DeleteEntity, UpdateEntities
    • WebAPIDataSource.DataOperations.cs — extended data retrieval and manipulation
    • WebAPIDataSource.EntityMethods.cs — entity discovery and CRUD orchestration
    • WebAPIDataSource.Structure.cs — GetEntitesList, CheckEntityExist, GetEntityStructure
    • WebAPIDataSource.Query.cs — query execution and scalar retrieval
    • WebAPIDataSource.QueryMethods.cs — extended query processing
    • WebAPIDataSource.PagingAsync.cs — pagination and async data retrieval
    • WebAPIDataSource.Bulk.cs — bulk operation stubs
    • WebAPIDataSource.BulkOperations.cs — enhanced batch processing
    • WebAPIDataSource.Scripting.cs — script execution and entity creation
    • WebAPIDataSource.ScriptTransactions.cs — transaction lifecycle stubs
    • WebAPIDataSource.WebAPI.cs — IWebAPIDataSource-specific ReadData
    • WebAPIDataSource.CoreInterface.cs — IDataSource interface implementation
    • WebAPIDataSource.CoreInterface.Fixed.cs — additional interface corrections
    • WebAPIDataSource.Interface.cs — supplementary interface contracts
    • WebAPIDataSource.Complete.cs — final assembly members
    • WebAPIDataSource.Main.cs — orchestration entry points
  • Helpers in WebAPI/Helpers/ (all IDisposable):
    • WebAPIConfigurationHelper — strongly-typed config properties, validation, endpoint/pagination settings
    • WebAPIAuthenticationHelper — OAuth2/Bearer/API Key/Basic auth with token refresh
    • WebAPIRequestHelper — centralized HttpClient execution with concurrency semaphore and retry
    • WebAPIDataHelper — URL construction, JSON parsing, ID extraction, cache-key helpers
    • WebAPICacheHelper — concurrent in-memory cache with TTL and cleanup timer
    • WebAPIRateLimitHelper — token bucket algorithm per-endpoint throttling
    • WebAPISchemaHelper — schema inference from JSON samples, entity validation
    • WebAPIErrorHelper — circuit breaker pattern, exponential backoff, error categorization
    • WebAPIInterfaces — IWebAPISchemaHelper, IWebAPIDataHelper contracts
  • Connection model: WebAPIConnectionProperties (with AuthTypeEnum, ValidateConfiguration(), GetValidationErrors()) / WebAPIDataConnection (normalizes IConnectionProperties).
  • Example connector: BeepDataSources/Connectors/SocialMedia/Twitter/TwitterDataSource.cs.

Updated Configuration Guide

This documentation uses the optimized WebAPIConnectionProperties class structure:

  • WebAPIConnectionProperties - Comprehensive Web API connection class with all required properties
  • AuthTypeEnum - Strongly-typed authentication types (None, ApiKey, Basic, Bearer, OAuth2)
  • Built-in validation - ValidateConfiguration() and GetValidationErrors() methods
  • Parameter management - GetParameterValue() and SetParameterValue() methods
  • Smart defaults - Automatic headers and authentication requirement detection
  • Complete interface compliance - Implements all IConnectionProperties members

Overview

The WebAPIDataSource is a comprehensive implementation of the IDataSource interface specifically designed for REST API integration within the BeepDM framework. It provides a unified way to interact with web APIs using familiar database-like operations while handling the complexities of HTTP communication, authentication, caching, and error recovery.

πŸ”„ Database-like Operations

Use familiar CRUD operations (Create, Read, Update, Delete) with any REST API

🔐 Multiple Authentication

OAuth2, Bearer tokens, API keys, Basic authentication, and custom providers

⚑ Circuit Breaker Pattern

Automatic failure recovery and resilience for production environments

💾 Intelligent Caching

Response caching with TTL and invalidation for improved performance

Γ°ΕΈΕ‘Β¦ Rate Limiting

Built-in throttling and request queuing to respect API limits

πŸ” Schema Inference

Automatic API schema discovery from JSON responses

Architecture

Partial Class Structure

The WebAPIDataSource follows a partial class pattern (20 files) for maintainability, mirroring the RDBSource approach:

WebAPIDataSource.cs              // Core state (properties/fields), constructor, dispose
WebAPIDataSource.CoreInterface.cs       // IDataSource interface + event handling
WebAPIDataSource.CoreInterface.Fixed.cs // Additional/corrected interface members
WebAPIDataSource.Interface.cs           // Supplementary interface contracts
WebAPIDataSource.Connection.cs          // Openconnection/Closeconnection, auth integration
WebAPIDataSource.Data.cs                // CRUD: GetEntity, InsertEntity, UpdateEntity, DeleteEntity
WebAPIDataSource.DataOperations.cs      // Extended data manipulation helpers
WebAPIDataSource.EntityMethods.cs       // Entity discovery and CRUD orchestration
WebAPIDataSource.Http.cs                // Centralized HTTP execution (GetAsync/PostAsync etc.)
WebAPIDataSource.Structure.cs           // Schema & entity structure discovery
WebAPIDataSource.Query.cs               // Query execution and scalar operations
WebAPIDataSource.QueryMethods.cs        // Extended query processing
WebAPIDataSource.PagingAsync.cs         // Pagination + async data retrieval
WebAPIDataSource.Bulk.cs                // Bulk operation stubs
WebAPIDataSource.BulkOperations.cs      // Enhanced batch processing
WebAPIDataSource.Scripting.cs           // Script execution and entity creation
WebAPIDataSource.ScriptTransactions.cs  // Transaction lifecycle stubs
WebAPIDataSource.WebAPI.cs              // IWebAPIDataSource-specific ReadData
WebAPIDataSource.Complete.cs            // Final assembly/completion members
WebAPIDataSource.Main.cs                // Additional orchestration entry points

Helper Classes

The implementation uses specialized helper classes for different concerns, all in the WebAPI/Helpers/ folder under TheTechIdea.Beep.WebAPI.Helpers namespace:

HelperFileKey Capabilities
WebAPIConfigurationHelperWebAPIConfigurationHelper.csBase URL, auth type, timeout, retry, caching, rate limit, pagination, proxy, SSL, response format β€” all from IConnectionProperties
WebAPIAuthenticationHelperWebAPIAuthenticationHelper.csToken refresh with EnsureAuthenticatedAsync(), header injection for None/ApiKey/Basic/Bearer/OAuth2
WebAPIRequestHelperWebAPIRequestHelper.csSendWithRetryAsync with SemaphoreSlim concurrency control, request cloning for retries
WebAPIDataHelperWebAPIDataHelper.csBuildEndpointUrl, ProcessApiResponse, ExtractIdFromResponse, GenerateDataCacheKey, ConvertToEntityStructure
WebAPICacheHelperWebAPICacheHelper.csConcurrent Dictionary-backed in-memory cache with TTL, cleanup timer, hit/miss stats
WebAPIRateLimitHelperWebAPIRateLimitHelper.csToken bucket algorithm per endpoint with WaitForCapacityAsync, stale bucket cleanup
WebAPISchemaHelperWebAPISchemaHelper.csInferSchemaFromJsonAsync, DiscoverEntitiesAsync, schema caching with configurable expiry
WebAPIErrorHelperWebAPIErrorHelper.csExponential backoff retry, circuit breaker (FailureThreshold/RecoveryTimeoutSeconds), transient error classification
WebAPIInterfacesWebAPIInterfaces.csIWebAPISchemaHelper, IWebAPIDataHelper, DataValidationResult

All helpers are composed in the WebAPIDataSource constructor and disposed in Dispose().

Configuration

Connection Properties

Configure your WebAPIDataSource using the WebAPIConnectionProperties class with built-in validation:

// Create WebAPI connection with comprehensive settings
var webApiConnection = new WebAPIConnectionProperties
{
    // Core connection settings
    ConnectionName = "GitHub API",
    ConnectionString = "https://api.github.com",
    AuthType = AuthTypeEnum.Bearer,
    ApiKey = "ghp_your-github-token",
    
    // Request configuration
    TimeoutMs = 30000,
    MaxRetries = 3,
    RetryIntervalMs = 1000,
    
    // Performance settings
    EnableCaching = true,
    CacheExpiryMinutes = 15,
    MaxConcurrentRequests = 10,
    
    // Rate limiting
    EnableRateLimit = true,
    RateLimitRequestsPerMinute = 60,
    
    // Response handling
    ResponseFormat = "json",
    UserAgent = "MyApp/1.0"
};

// Add custom headers
webApiConnection.Headers.Add(new WebApiHeader 
{ 
    Headername = "Accept", 
    Headervalue = "application/vnd.github.v3+json" 
});

// Set additional parameters
webApiConnection.SetParameterValue("DefaultPageSize", "50");
webApiConnection.SetParameterValue("MaxPageSize", "100");

// Validate configuration
if (webApiConnection.ValidateConfiguration())
{
    Console.WriteLine("Configuration is valid");
}
else
{
    Console.WriteLine($"Configuration errors: {webApiConnection.GetValidationErrors()}");
}

Authentication Types

WebAPIConnectionProperties supports multiple authentication methods through the AuthTypeEnum:

// No Authentication
var noAuthConnection = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.publicdata.com",
    AuthType = AuthTypeEnum.None
};

// API Key Authentication
var apiKeyConnection = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.service.com",
    AuthType = AuthTypeEnum.ApiKey,
    ApiKey = "your-api-key",
    ApiKeyHeader = "X-API-Key" // Default, can be customized
};

// Basic Authentication
var basicAuthConnection = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.internal.com",
    AuthType = AuthTypeEnum.Basic,
    UserID = "username",
    Password = "password"
};

// Bearer Token Authentication
var bearerConnection = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.service.com",
    AuthType = AuthTypeEnum.Bearer,
    ApiKey = "your-bearer-token" // Static token
};

// OAuth2 Authentication
var oauth2Connection = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.service.com",
    AuthType = AuthTypeEnum.OAuth2,
    ClientId = "your-client-id",
    ClientSecret = "your-client-secret",
    TokenUrl = "https://auth.service.com/oauth/token",
    GrantType = "client_credentials", // or "password", "authorization_code"
    Scope = "read write" // Optional
};

Usage Examples

Basic Setup

// Initialize the data source
var webApiDS = new WebAPIDataSource("MyAPI", logger, dmeEditor, DataSourceType.WebApi, errorObject);

// Open connection (performs authentication)
var connectionResult = webApiDS.Openconnection();

// Get list of available entities
var entities = webApiDS.GetEntitesList();

// Get entity structure
var userStructure = webApiDS.GetEntityStructure("Users", false);

GitHub API Integration

Advanced Configuration

Configure advanced settings for production environments:

var advancedConnection = new WebAPIConnectionProperties
{
    ConnectionName = "Production API",
    ConnectionString = "https://api.production.com/v2",
    AuthType = AuthTypeEnum.OAuth2,
    
    // OAuth2 settings
    ClientId = "prod-client-id",
    ClientSecret = Environment.GetEnvironmentVariable("API_CLIENT_SECRET"),
    TokenUrl = "https://auth.production.com/oauth/token",
    GrantType = "client_credentials",
    Scope = "api:read api:write",
    
    // Performance tuning
    TimeoutMs = 60000, // 60 seconds for slow APIs
    MaxRetries = 5,
    RetryIntervalMs = 2000, // 2 second delay between retries
    MaxConcurrentRequests = 20,
    
    // Caching strategy
    EnableCaching = true,
    CacheExpiryMinutes = 30,
    
    // Rate limiting
    EnableRateLimit = true,
    RateLimitRequestsPerMinute = 120,
    
    // Security settings
    ValidateServerCertificate = true,
    IgnoreSSLErrors = false,
    
    // Proxy configuration (if needed)
    UseProxy = true,
    ProxyUrl = "http://corporate-proxy.com",
    ProxyPort = 8080,
    UseDefaultProxyCredentials = true,
    
    // Response handling
    ResponseFormat = "json",
    DataPath = "$.data", // JSONPath to extract data
    TotalCountPath = "$.meta.total", // JSONPath for pagination
    
    // Pagination
    PageNumberParameter = "page",
    PageSizeParameter = "per_page",
    DefaultPageSize = 50,
    MaxPageSize = 200,
    
    // Custom headers
    UserAgent = "MyApp/2.1.0 (+https://mycompany.com/contact)"
};

// Add authentication header template
advancedConnection.Headers.Add(new WebApiHeader 
{ 
    Headername = "Accept", 
    Headervalue = "application/vnd.api+json" 
});

// Store endpoint mappings
advancedConnection.SetParameterValue("Endpoints.Users", "/api/v2/users");
advancedConnection.SetParameterValue("Endpoints.Orders", "/api/v2/orders");
advancedConnection.SetParameterValue("Endpoints.Products", "/api/v2/products");

// Validate before use
if (!advancedConnection.ValidateConfiguration())
{
    throw new InvalidOperationException($"Invalid API configuration: {advancedConnection.GetValidationErrors()}");
}

GitHub API Integration

GitHub API Configuration

// Configure for GitHub API v4 (GraphQL) and v3 (REST)
var githubConnection = new WebAPIConnectionProperties
{
    ConnectionName = "GitHub API",
    ConnectionString = "https://api.github.com",
    AuthType = AuthTypeEnum.Bearer,
    ApiKey = "ghp_your_personal_access_token",
    
    // GitHub-specific settings
    TimeoutMs = 30000,
    MaxRetries = 3,
    RetryIntervalMs = 1000,
    RateLimitRequestsPerMinute = 60, // GitHub's rate limit
    
    // Response settings
    ResponseFormat = "json",
    UserAgent = "MyApp/1.0 (https://github.com/myuser/myapp)",
    
    // Pagination for GitHub API
    PageSizeParameter = "per_page",
    PageNumberParameter = "page",
    DefaultPageSize = 30,
    MaxPageSize = 100
};

// Add GitHub-specific headers
githubConnection.Headers.Add(new WebApiHeader 
{ 
    Headername = "Accept", 
    Headervalue = "application/vnd.github.v3+json" 
});

// Configure endpoint mappings
githubConnection.SetParameterValue("Repos.List", "/user/repos");
githubConnection.SetParameterValue("Repos.Get", "/repos/{owner}/{repo}");
githubConnection.SetParameterValue("Issues.List", "/repos/{owner}/{repo}/issues");
githubConnection.SetParameterValue("Pulls.List", "/repos/{owner}/{repo}/pulls");
githubConnection.SetParameterValue("Commits.List", "/repos/{owner}/{repo}/commits");

// Validate configuration
if (githubConnection.ValidateConfiguration())
{
    Console.WriteLine("GitHub API configuration is valid");
}

Usage Example

// Initialize data source with GitHub connection
var githubDataSource = new WebAPIDataSource("GitHub", logger, dmeEditor, DataSourceType.WebApi, errorObject);
githubDataSource.ConnectionProp = githubConnection;

// Open connection
var connectionResult = githubDataSource.Openconnection();
if (connectionResult == ConnectionState.Open)
{
    // Get repository information
    var filters = new List<AppFilter> 
    {
        new AppFilter {FieldName = "owner", FilterValue = "microsoft", Operator = "=" },
        new AppFilter {FieldName = "repo", FilterValue = "vscode", Operator = "=" }
    };

    var repoData = githubDataSource.GetEntity("repos", filters);
    
    // Get issues with pagination
    var issueFilters = new List<AppFilter>
    {
        new AppFilter {FieldName = "owner", FilterValue = "microsoft", Operator = "=" },
        new AppFilter {FieldName = "repo", FilterValue = "vscode", Operator = "=" },
        new AppFilter {FieldName = "state", FilterValue = "open", Operator = "=" }
    };
    
    var pagedIssues = githubDataSource.GetEntity("issues", issueFilters, 1, 50);
    
    // Execute custom query
    var recentCommits = githubDataSource.RunQuery("GET /repos/microsoft/vscode/commits?since=2024-01-01T00:00:00Z");
}

Twitter API v2

Twitter API Configuration

// Configure for Twitter API v2 using standard ConnectionProperties
ConnectionProp.ConnectionString = "https://api.twitter.com/2";
ConnectionProp.ApiKey = "your-twitter-bearer-token";

// Add authorization header
ConnectionProp.Headers.Add(new WebApiHeader 
{ 
    Headername = "Authorization", 
    Headervalue = "Bearer your-twitter-bearer-token" 
});

// Define endpoints using Parameters
ConnectionProp.Parameters = "Endpoints.Tweets.Get=/tweets/search/recent;Endpoints.Users.Get=/users/by/username/{username};Endpoints.Spaces.Get=/spaces/{id}";

// Or using WebAPIConnectionProperties
var webApiProps = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.twitter.com/2",
    AuthType = "Bearer",
    ApiKey = "your-twitter-bearer-token"
};

Usage Example

// Search for recent tweets
var tweetFilters = new List<AppFilter> {
    new AppFilter {FieldName = "query", FilterValue = "#CSharp", Operator = "=" },
    new AppFilter {FieldName = "max_results", FilterValue = "100", Operator = "=" }
};

var tweets = webApiDS.GetEntity("Tweets", tweetFilters);

// Get user information
var userFilters = new List<AppFilter> {
    new AppFilter {FieldName = "username", FilterValue = "GitHub", Operator = "=" }
};

var userData = webApiDS.GetEntity("Users", userFilters);

Stripe API (Payment Processing)

Stripe API Configuration

// Configure for Stripe API using standard ConnectionProperties
ConnectionProp.ConnectionString = "https://api.stripe.com/v1";
ConnectionProp.ApiKey = "sk_test_your-stripe-secret-key";

// Add authorization header
ConnectionProp.Headers.Add(new WebApiHeader 
{ 
    Headername = "Authorization", 
    Headervalue = "Bearer sk_test_your-stripe-secret-key" 
});

// Define endpoints using Parameters
ConnectionProp.Parameters = "Endpoints.Customers.Get=/customers;Endpoints.Customers.Post=/customers;Endpoints.Charges.Get=/charges;Endpoints.Invoices.Get=/invoices";

// Or using WebAPIConnectionProperties
var webApiProps = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.stripe.com/v1",
    AuthType = "Bearer",
    ApiKey = "sk_test_your-stripe-secret-key"
};

Usage Example

// Get customer list
var customers = webApiDS.GetEntity("Customers", null);

// Create new customer
var newCustomer = new {
    email = "customer@example.com",
    name = "John Doe",
    description = "New customer"
};

var insertResult = webApiDS.InsertEntity("Customers", newCustomer);

// Get charges with filtering
var chargeFilters = new List<AppFilter> {
    new AppFilter {FieldName = "customer", FilterValue = "cus_1234567890", Operator = "=" },
    new AppFilter {FieldName = "limit", FilterValue = "50", Operator = "=" }
};

var charges = webApiDS.GetEntity("Charges", chargeFilters);

Company Internal API

Internal API Configuration

// Configure for internal company API using standard ConnectionProperties
ConnectionProp.ConnectionString = "https://api.company.internal/v2";
ConnectionProp.UserID = "company-app-client-id";
ConnectionProp.Password = "company-app-client-secret";

// Store OAuth2 configuration in Parameters
ConnectionProp.Parameters = "AuthType=OAuth2;TokenUrl=https://auth.company.internal/oauth/token;GrantType=client_credentials";

// Define endpoints using Parameters
ConnectionProp.Parameters += ";Endpoints.Employees.Get=/hr/employees;Endpoints.Employees.Post=/hr/employees;Endpoints.Projects.Get=/pm/projects;Endpoints.Timesheets.Get=/hr/timesheets";

// Or using WebAPIConnectionProperties
var webApiProps = new WebAPIConnectionProperties
{
    ConnectionString = "https://api.company.internal/v2",
    AuthType = "OAuth2",
    ClientId = "company-app-client-id",
    ClientSecret = "company-app-client-secret",
    TokenUrl = "https://auth.company.internal/oauth/token",
    GrantType = "client_credentials"
};

Usage Example

// Get employee directory
var employees = webApiDS.GetEntity("Employees", null);

// Get projects with filtering
var projectFilters = new List<AppFilter> {
    new AppFilter {FieldName = "status", FilterValue = "active", Operator = "=" },
    new AppFilter {FieldName = "department", FilterValue = "engineering", Operator = "=" }
};

var projects = webApiDS.GetEntity("Projects", projectFilters);

// Submit timesheet entry
var timesheetEntry = new {
    employee_id = "12345",
    project_id = "PROJ-001",
    hours = 8.0,
    date = DateTime.Today.ToString("yyyy-MM-dd"),
    description = "Feature development"
};

var submitResult = webApiDS.InsertEntity("Timesheets", timesheetEntry);

RESTful CRUD Operations

// Full CRUD example with a generic REST API

// CREATE - Insert new record
var newRecord = new {
    name = "John Doe",
    email = "john.doe@example.com",
    department = "Engineering"
};
var insertResult = webApiDS.InsertEntity("Users", newRecord);

// READ - Get all records
var allUsers = webApiDS.GetEntity("Users", null);

// READ - Get with filtering
var filters = new List<AppFilter> {
    new AppFilter {FieldName = "department", FilterValue = "Engineering", Operator = "=" }
};
var engineers = webApiDS.GetEntity("Users", filters);

// READ - Get single record by ID
var userFilters = new List<AppFilter> {
    new AppFilter {FieldName = "id", FilterValue = "123", Operator = "=" }
};
var user = webApiDS.GetEntity("Users", userFilters);

// UPDATE - Modify existing record
var updatedUser = new {
    id = 123,
    name = "John Smith",
    email = "john.smith@example.com",
    department = "Engineering"
};
var updateResult = webApiDS.UpdateEntity("Users", updatedUser);

// DELETE - Remove record
var deleteResult = webApiDS.DeleteEntity("Users", updatedUser);

Advanced Features

Circuit Breaker Pattern

The WebAPIDataSource automatically implements circuit breaker functionality:

// Circuit breaker automatically handles failures
// - Closed: Normal operation
// - Open: Failing fast after repeated failures
// - Half-Open: Testing recovery

// The circuit breaker is automatically managed by WebAPIErrorHelper
// and integrated into all HTTP requests via WebAPIRequestHelper

Performance Optimization

// High-performance configuration for heavy workloads
var performanceConnection = new WebAPIConnectionProperties
{
    ConnectionName = "High Performance API",
    ConnectionString = "https://api.high-volume.com/v1",
    AuthType = AuthTypeEnum.ApiKey,
    ApiKey = "your-high-perf-key",
    
    // Aggressive performance settings
    TimeoutMs = 10000, // Quick timeout for fast APIs
    MaxRetries = 1, // Minimal retries for speed
    RetryIntervalMs = 500, // Fast retry
    MaxConcurrentRequests = 50, // High concurrency
    
    // Optimized caching
    EnableCaching = true,
    CacheExpiryMinutes = 5, // Short cache for fresh data
    
    // Aggressive rate limiting
    EnableRateLimit = true,
    RateLimitRequestsPerMinute = 1000,
    
    // Compression for bandwidth
    EnableCompression = true,
    
    // Minimal response processing
    ResponseFormat = "json",
    DataPath = "$", // Direct response, no nesting
    
    // Large page sizes
    DefaultPageSize = 500,
    MaxPageSize = 1000,
    
    UserAgent = "HighPerf-Client/1.0"
};

// Minimal headers for performance
performanceConnection.Headers.Clear();
performanceConnection.Headers.Add(new WebApiHeader { Headername = "Accept", Headervalue = "application/json" });
performanceConnection.Headers.Add(new WebApiHeader { Headername = "Accept-Encoding", Headervalue = "gzip, deflate" });

Configuration Validation and Error Handling

// Comprehensive validation example
public static WebAPIConnectionProperties CreateValidatedConnection(string configName)
{
    var connection = new WebAPIConnectionProperties();
    
    try
    {
        // Load configuration from various sources
        connection.ConnectionName = configName;
        connection.ConnectionString = Configuration.GetConnectionString(configName);
        connection.AuthType = Enum.Parse<AuthTypeEnum>(Configuration[$"{configName}:AuthType"]);
        
        // Set auth-specific properties
        switch (connection.AuthType)
        {
            case AuthTypeEnum.ApiKey:
                connection.ApiKey = Configuration[$"{configName}:ApiKey"];
                connection.ApiKeyHeader = Configuration[$"{configName}:ApiKeyHeader"] ?? "X-API-Key";
                break;
                
            case AuthTypeEnum.Basic:
                connection.UserID = Configuration[$"{configName}:Username"];
                connection.Password = Configuration[$"{configName}:Password"];
                break;
                
            case AuthTypeEnum.OAuth2:
                connection.ClientId = Configuration[$"{configName}:ClientId"];
                connection.ClientSecret = Configuration[$"{configName}:ClientSecret"];
                connection.TokenUrl = Configuration[$"{configName}:TokenUrl"];
                connection.Scope = Configuration[$"{configName}:Scope"];
                break;
        }
        
        // Apply environment-specific settings
        var environment = Configuration["Environment"];
        if (environment == "Production")
        {
            connection.TimeoutMs = 60000;
            connection.MaxRetries = 3;
            connection.ValidateServerCertificate = true;
        }
        else if (environment == "Development")
        {
            connection.TimeoutMs = 30000;
            connection.MaxRetries = 1;
            connection.IgnoreSSLErrors = true; // Only for dev!
        }
        
        // Validate the configuration
        if (!connection.ValidateConfiguration())
        {
            var errors = connection.GetValidationErrors();
            throw new ConfigurationException($"Invalid {configName} configuration: {errors}");
        }
        
        Logger.Information($"Successfully configured {configName} connection");
        return connection;
    }
    catch (Exception ex)
    {
        Logger.Error($"Failed to create {configName} connection: {ex.Message}");
        throw;
    }
}

// Usage
var githubConnection = CreateValidatedConnection("GitHub");
var stripeConnection = CreateValidatedConnection("Stripe");

Custom Authentication

// Implement custom authentication by extending WebAPIAuthenticationHelper
public class CustomAuthHelper : WebAPIAuthenticationHelper
{
    public override async Task<bool> EnsureAuthenticatedAsync()
    {
        // Custom authentication logic
        var token = await GetCustomToken();
        // Set authentication headers
        return true;
    }
}

Best Practices

Òő ï¸ Security Considerations

  • Never store API keys or secrets in plain text configuration files
  • Use environment variables or secure credential stores
  • Implement proper token refresh logic for long-running applications
  • Validate SSL certificates for production environments

βœ… Performance Optimization

  • Enable caching for frequently accessed data
  • Use pagination for large datasets
  • Configure appropriate timeouts and retry policies
  • Monitor rate limits and implement backoff strategies

Error Handling

// Always check error status after operations
var result = webApiDS.InsertEntity("Users", userData);
if (result.Flag == Errors.Failed)
{
    Logger.WriteLog($"Operation failed: {result.Message}");
    // Handle error appropriately
}

// Use try-catch for comprehensive error handling
try
{
    var data = webApiDS.GetEntity("Users", filters);
}
catch (HttpRequestException ex)
{
    Logger.WriteLog($"HTTP Error: {ex.Message}");
    // Handle network errors
}
catch (Exception ex)
{
    Logger.WriteLog($"Unexpected error: {ex.Message}");
    // Handle other errors
}

Connection Management

// Always open connection before use
if (webApiDS.ConnectionStatus != ConnectionState.Open)
{
    var result = webApiDS.Openconnection();
    if (result == ConnectionState.Open)
    {
        // Connection successful
    }
}

// Close connection when done
webApiDS.Closeconnection();

// Use using statement for automatic disposal
using (var ds = new WebAPIDataSource(name, logger, editor, type, errors))
{
    // Use data source
} // Automatically disposed

Troubleshooting

Common Issues

Troubleshooting Guide

// Comprehensive troubleshooting helper
public static class WebAPITroubleshooter
{
    public static void DiagnoseConnection(WebAPIConnectionProperties connection)
    {
        Console.WriteLine("=== WebAPI Connection Diagnostics ===");
        
        // Basic validation
        Console.WriteLine($"Connection Name: {connection.ConnectionName ?? "Not Set"}");
        Console.WriteLine($"Connection String: {connection.ConnectionString ?? "Not Set"}");
        Console.WriteLine($"Auth Type: {connection.AuthType}");
        
        // Validate configuration
        if (connection.ValidateConfiguration())
        {
            Console.WriteLine("Γ’Ε“β€œ Configuration validation passed");
        }
        else
        {
            Console.WriteLine($"Γ’Ε“β€” Configuration errors: {connection.GetValidationErrors()}");
        }
        
        // Check authentication setup
        CheckAuthentication(connection);
        
        // Check network settings
        CheckNetworkSettings(connection);
        
        // Check performance settings
        CheckPerformanceSettings(connection);
    }
    
    private static void CheckAuthentication(WebAPIConnectionProperties connection)
    {
        Console.WriteLine("\n--- Authentication Check ---");
        
        switch (connection.AuthType)
        {
            case AuthTypeEnum.None:
                Console.WriteLine("Γ’Ε“β€œ No authentication required");
                break;
                
            case AuthTypeEnum.ApiKey:
                Console.WriteLine($"API Key: {(!string.IsNullOrEmpty(connection.ApiKey) ? "Set" : "Γ’Ε“β€” Not Set")}");
                Console.WriteLine($"API Key Header: {connection.ApiKeyHeader}");
                break;
                
            case AuthTypeEnum.Basic:
                Console.WriteLine($"Username: {(!string.IsNullOrEmpty(connection.UserID) ? "Set" : "Γ’Ε“β€” Not Set")}");
                Console.WriteLine($"Password: {(!string.IsNullOrEmpty(connection.Password) ? "Set" : "Γ’Ε“β€” Not Set")}");
                break;
                
            case AuthTypeEnum.Bearer:
                Console.WriteLine($"Bearer Token: {(!string.IsNullOrEmpty(connection.ApiKey) ? "Set" : "Γ’Ε“β€” Not Set")}");
                break;
                
            case AuthTypeEnum.OAuth2:
                Console.WriteLine($"Client ID: {(!string.IsNullOrEmpty(connection.ClientId) ? "Set" : "Γ’Ε“β€” Not Set")}");
                Console.WriteLine($"Client Secret: {(!string.IsNullOrEmpty(connection.ClientSecret) ? "Set" : "Γ’Ε“β€” Not Set")}");
                Console.WriteLine($"Token URL: {connection.TokenUrl ?? "Γ’Ε“β€” Not Set"}");
                Console.WriteLine($"Grant Type: {connection.GrantType}");
                Console.WriteLine($"Scope: {connection.Scope ?? "Not Set"}");
                break;
        }
    }
    
    private static void CheckNetworkSettings(WebAPIConnectionProperties connection)
    {
        Console.WriteLine("\n--- Network Settings ---");
        Console.WriteLine($"Timeout: {connection.TimeoutMs}ms");
        Console.WriteLine($"Max Retries: {connection.MaxRetries}");
        Console.WriteLine($"Retry Interval: {connection.RetryIntervalMs}ms");
        Console.WriteLine($"SSL Validation: {(connection.ValidateServerCertificate ? "Enabled" : "Disabled")}");
        Console.WriteLine($"Ignore SSL Errors: {(connection.IgnoreSSLErrors ? "Yes" : "No")}");
        
        if (connection.UseProxy)
        {
            Console.WriteLine($"Proxy: {connection.ProxyUrl}:{connection.ProxyPort}");
            Console.WriteLine($"Proxy Credentials: {(connection.UseDefaultProxyCredentials ? "Default" : "Custom")}");
        }
        else
        {
            Console.WriteLine("Proxy: Not Used");
        }
    }
    
    private static void CheckPerformanceSettings(WebAPIConnectionProperties connection)
    {
        Console.WriteLine("\n--- Performance Settings ---");
        Console.WriteLine($"Caching: {(connection.EnableCaching ? "Enabled" : "Disabled")}");
        if (connection.EnableCaching)
        {
            Console.WriteLine($"Cache Expiry: {connection.CacheExpiryMinutes} minutes");
        }
        
        Console.WriteLine($"Rate Limiting: {(connection.EnableRateLimit ? "Enabled" : "Disabled")}");
        if (connection.EnableRateLimit)
        {
            Console.WriteLine($"Rate Limit: {connection.RateLimitRequestsPerMinute} requests/minute");
        }
        
        Console.WriteLine($"Max Concurrent Requests: {connection.MaxConcurrentRequests}");
        Console.WriteLine($"Compression: {(connection.EnableCompression ? "Enabled" : "Disabled")}");
        Console.WriteLine($"Default Page Size: {connection.DefaultPageSize}");
        Console.WriteLine($"Max Page Size: {connection.MaxPageSize}");
        
        Console.WriteLine($"\nHeaders ({connection.Headers.Count}):");
        foreach (var header in connection.Headers)
        {
            Console.WriteLine($"  {header.Headername}: {header.Headervalue}");
        }
    }
}

// Usage
var connection = new WebAPIConnectionProperties { /* your config */ };
WebAPITroubleshooter.DiagnoseConnection(connection);

Schema Inference Problems

// Force schema refresh
var structure = webApiDS.GetEntityStructure("EntityName", true);

// Manually define schema if inference fails
var customStructure = new EntityStructure
{
    EntityName = "CustomEntity",
    Fields = new List<EntityField> {
        new EntityField {FieldName = "id", Fieldtype = "System.Int32" },
        new EntityField {FieldName = "name", Fieldtype = "System.String" }
    }
};

API Reference

Class: WebAPIDataSource

public partial class WebAPIDataSource : IWebAPIDataSource, IDisposable β€” 20 partial files, 34 implemented methods across 8 files (12 partials are stubs for future implementation).

Properties

PropertyTypeDefaultDescription
ColumnDelimiterstring"Delimiter used to separate columns
ParameterDelimiterstring":"Delimiter used for parameters
GuidIDstringGuid.NewGuid()Unique identifier
DatasourceTypeDataSourceTypeWebApiType of data source
CategoryDatasourceCategoryWEBAPICategory of data source
DataconnectionIDataConnectionβ€”Data connection interface
DatasourceNamestringβ€”Name of the data source
ErrorObjectIErrorsInfoβ€”Error handling object
Idstringβ€”Secondary identifier
LoggerIDMLoggerβ€”Logger instance
EntitiesNamesList<string>new()Entity name list
EntitiesList<EntityStructure>new()Entity structures
DMEEditorIDMEEditorβ€”DME editor reference
ConnectionStatusConnectionStateClosedCurrent connection state
ApiKeystringβ€”API key for auth
Resourcestringβ€”Resource endpoint
ParametersDictionary<string,string>new()Request parameters

Event

  • event EventHandler<PassedArgs> PassEvent β€” Raised when a specific action or event is passed

Constructor

WebAPIDataSource(string datasourcename, IDMLogger logger, IDMEEditor dmeEditor, DataSourceType databasetype, IErrorsInfo errorObject)

Initializes helpers (WebAPIConfigurationHelper, WebAPIAuthenticationHelper, WebAPIRequestHelper, WebAPICacheHelper, WebAPIDataHelper, WebAPIRateLimitHelper, WebAPISchemaHelper, WebAPIErrorHelper), creates shared HttpClient, loads saved connection from ConfigEditor.

Implemented Methods by Partial File

Connection.cs (5 methods)
MethodReturnDescription
Openconnection()ConnectionStateOpens connection, ensures authentication via _authHelper.EnsureAuthenticatedAsync()
Closeconnection()ConnectionStateCloses the connection, sets state to Closed
BeginTransaction(PassedArgs args)IErrorsInfoBegins a transaction (stub)
EndTransaction(PassedArgs args)IErrorsInfoEnds a transaction (stub)
Commit(PassedArgs args)IErrorsInfoCommits a transaction (stub)
Data.cs (7 methods β€” core CRUD)
MethodReturnDescription
GetEntity(string, List<AppFilter>)IEnumerable<object>Retrieves entities with optional filters. Delegates to GetEntityAsync
GetEntity(string, List<AppFilter>, int, int)PagedResultPaged entity retrieval with page number and page size
GetEntityAsync(string, List<AppFilter>)Task<IEnumerable<object>>Async entity retrieval with endpoint resolution, rate limiting, and caching
InsertEntity(string, object)IErrorsInfoCreates a new record via POST
UpdateEntity(string, object)IErrorsInfoUpdates a record via PUT
DeleteEntity(string, object)IErrorsInfoDeletes a record via DELETE
UpdateEntities(string, object, IProgress<PassedArgs>)IErrorsInfoBatch update with progress reporting
Http.cs (11 methods β€” HTTP convenience layer)
MethodReturnDescription
GetAsync(string, Dictionary?, Dictionary?, CancellationToken)Task<HttpResponseMessage>HTTP GET with optional query params and headers
GetAsync<T>(string, Dictionary?, Dictionary?, CancellationToken)Task<T>HTTP GET with deserialization to T
PostAsync(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<HttpResponseMessage>HTTP POST with JSON body
PostAsync<T>(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<T>HTTP POST with deserialization
PutAsync(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<HttpResponseMessage>HTTP PUT with JSON body
PutAsync<T>(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<T>HTTP PUT with deserialization
PatchAsync(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<HttpResponseMessage>HTTP PATCH with JSON body
PatchAsync<T>(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<T>HTTP PATCH with deserialization
DeleteAsync(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<HttpResponseMessage>HTTP DELETE with optional query params
DeleteAsync<T>(string, object?, Dictionary?, Dictionary?, CancellationToken)Task<T>HTTP DELETE with deserialization

All HTTP methods auto-apply auth headers via _authHelper.AddAuthenticationHeaders(), ensure auth state, and add default headers from config. The private helper BuildUrlWithQuery(string, Dictionary) constructs URLs with query string parameters.

Structure.cs (11 methods β€” schema & entity structure)
MethodReturnDescription
GetEntitesList()IEnumerable<string>Returns configured entity names from endpoint config
CheckEntityExist(string)boolChecks if an entity is configured
GetEntityIdx(string)intGets index of entity in Entities list
GetEntityStructure(string, bool)EntityStructureGets entity schema, optionally from API response inference
GetEntityStructure(EntityStructure, bool)EntityStructureOverload accepting EntityStructure object
GetEntityType(string)TypeGets CLR type for entity
GetEntityforeignkeys(string, string)IEnumerable<RelationShipKeys>Gets foreign key relationships (stub)
GetChildTablesList(string, string, string)IEnumerable<ChildRelation>Gets child table list (stub)
CreateEntityAs(EntityStructure)boolCreates entity definition
Query.cs (4 methods)
MethodReturnDescription
RunQuery(string)IEnumerable<object>Executes a query string (delegates to HTTP GET)
GetScalar(string)doubleExecutes scalar query
GetScalarAsync(string)Task<double>Async scalar query
ExecuteSql(string)IErrorsInfoExecutes SQL-like command
Scripting.cs (3 methods)
MethodReturnDescription
RunScript(ETLScriptDet)IErrorsInfoRuns an ETL script
GetCreateEntityScript(List<EntityStructure>?)IEnumerable<ETLScriptDet>Generates create-entity script
CreateEntities(List<EntityStructure>)IErrorsInfoCreates entities from script
WebAPI.cs (1 method)
MethodReturnDescription
ReadData(bool, int, int)Task<IEnumerable<object>>IWebAPIDataSource-specific data reading with header flag and line range

Empty / Stub Partial Files (12 files)

The following partial class files exist for future implementation but currently contain no method bodies:

  • WebAPIDataSource.CoreInterface.cs
  • WebAPIDataSource.CoreInterface.Fixed.cs
  • WebAPIDataSource.Interface.cs
  • WebAPIDataSource.DataOperations.cs
  • WebAPIDataSource.EntityMethods.cs
  • WebAPIDataSource.QueryMethods.cs
  • WebAPIDataSource.PagingAsync.cs
  • WebAPIDataSource.Bulk.cs
  • WebAPIDataSource.BulkOperations.cs
  • WebAPIDataSource.ScriptTransactions.cs
  • WebAPIDataSource.Complete.cs
  • WebAPIDataSource.Main.cs

Class: WebAPIConnectionProperties

public class WebAPIConnectionProperties : IConnectionProperties β€” 707 lines, 50+ properties with validation.

Core Connection Properties

PropertyTypeDefault
IDint0
GuidIDstringGuid.NewGuid()
ConnectionNamestringnull
ConnectionStringstringnull
Databasestringnull
DatabaseTypeDataSourceTypeWebApi
CategoryDatasourceCategoryWEBAPI
DriverNamestringnull
DriverVersionstringnull
Hoststringnull
Portint0
UserIDstringnull
Passwordstringnull
SchemaNamestringnull
Parametersstringnull
HeadersList<WebApiHeader>new() (defaults: Accept, User-Agent)
EntitiesList<EntityStructure>new()

Web API Specific Properties

PropertyTypeDefaultDescription
ApiVersionstring"v1.0"API version string
AuthTypeAuthTypeEnumNoneAuthentication mode (triggers UpdateAuthenticationRequirements())
ClientIdstringnullOAuth2 client ID
ClientSecretstringnullOAuth2 client secret
AuthUrlstringnullOAuth2 authorization URL
TokenUrlstringnullOAuth2 token endpoint
ScopestringnullOAuth2 scope
GrantTypestring"client_credentials"OAuth2 grant type
ApiKeyHeaderstring"X-API-Key"Header name for API key auth
ApiKeystringnullAPI key / bearer token value
RedirectUristringnullOAuth2 redirect URI
AuthCodestringnullOAuth2 authorization code
BearerTokenstringnullStatic bearer token
AccessTokenstringmaps to ApiKeyInstagram compat alias
AppIdstringmaps to ClientIdInstagram compat alias
AppSecretstringmaps to ClientSecretInstagram compat alias
ConsumerKeystringmaps to ClientIdTwitter/OAuth compat alias
ConsumerSecretstringmaps to ClientSecretTwitter/OAuth compat alias

Configuration Settings

PropertyTypeDefaultRange
TimeoutMsint30000β‰₯ 1000
MaxRetriesint3β‰₯ 0
RetryIntervalMsint1000β‰₯ 0
RetryCountint3β‰₯ 0
RetryDelayMsint1000β‰₯ 0
CacheExpiryMinutesint15β‰₯ 1
MaxConcurrentRequestsint10β‰₯ 1
EnableCachingbooltrueβ€”
EnableCompressionbooltrueβ€”
UserAgentstring"BeepDM-WebAPI/1.0"β€”
RequiresAuthenticationboolfalseSet by AuthType
RequiresTokenRefreshboolfalsetrue for Bearer/OAuth2

Proxy Settings

PropertyTypeDefault
UseProxyboolfalse
ProxyUrlstringnull
ProxyPortint0
ProxyUserstringnull
ProxyPasswordstringnull
BypassProxyOnLocalboolfalse
UseDefaultProxyCredentialsboolfalse

SSL / Certificate Settings

PropertyTypeDefault
IgnoreSSLErrorsboolfalse
ValidateServerCertificatebooltrue
ClientCertificatePathstringnull
ClientCertificatePasswordstringnull
CertificatePathstringnull

Rate Limiting

PropertyTypeDefault
RateLimitRequestsPerMinuteint60
EnableRateLimitbooltrue

Response Handling

PropertyTypeDefaultDescription
ResponseFormatstring"json"Expected format: json, xml, csv, text
DataPathstringnullJSONPath/XPath to extract data
TotalCountPathstringnullJSONPath/XPath for total count

Pagination Settings

PropertyTypeDefault
PageNumberParameterstring"page"
PageSizeParameterstring"limit"
DefaultPageSizeint100
MaxPageSizeint1000

Methods

MethodReturnDescription
ValidateConfiguration()boolValidates required properties for the current AuthType
GetValidationErrors()stringReturns detailed error messages for missing configuration
GetParameterValue(string)string?Gets a parameter from the Parameters string by name
SetParameterValue(string, string)voidSets a parameter in the Parameters string

AuthTypeEnum

ValueRequiresToken Refresh
Noneβ€”No
ApiKeyApiKeyNo
BasicUserID + PasswordNo
BearerKeyToken or ApiKeyYes
OAuth2ClientId + ClientSecret + TokenUrlYes

Class: WebAPIDataConnection

public class WebAPIDataConnection : IDataConnection β€” 643 lines, full connection management.

Properties

PropertyTypeDescription
ConnectionPropIConnectionPropertiesConnection properties (cast to WebAPIConnectionProperties via WebAPIProperties)
ConnectionStatusConnectionStateCurrent state (default: Closed)
LoggerIDMLoggerLogger instance
ErrorObjectIErrorsInfoError information
DMEEditorIDMEEditorDME editor reference
IdstringUnique identifier (Guid)
ConnectionStringstringBuilds from properties / parses into properties
DatabaseTypeDataSourceTypeWebApi
WebAPIPropertiesWebAPIConnectionProperties?Cast accessor for ConnectionProp

Methods

MethodReturnDescription
OpenConnection()ConnectionStateOpens connection with current properties (validates + tests URL)
OpenConnection(IConnectionProperties)ConnectionStateOpens connection with specific properties (normalizes to WebAPIConnectionProperties)
OpenConnection(DataSourceType, string)ConnectionStateOpens connection from connection string
OpenConnection(DataSourceType, string, int, string, string, string, string)ConnectionStateOpens connection with individual parameters
CloseConn()ConnectionStateCloses connection, sets state to Closed
ReplaceValueFromConnectionString()stringLegacy method, replaces {Host}/{UserID} etc. placeholders

Static method:

  • static NormalizeConnectionProperties(IConnectionProperties) β€” Converts any IConnectionProperties to WebAPIConnectionProperties, preserving all mapped fields

Helper Classes β€” Full API Reference

All helpers reside in TheTechIdea.Beep.WebAPI.Helpers namespace under WebAPI/Helpers/.

WebAPIConfigurationHelper

public class WebAPIConfigurationHelper : IDisposable (813 lines)

Properties: BaseUrl, ApiVersion, AuthenticationType, TimeoutMs, MaxRetries, RetryDelayMs, CacheEnabled, CacheDurationMinutes, RateLimitEnabled, RequestsPerSecond, PagingEnabled, PageSize, MaxConcurrentRequests β€” all read-only, driven from WebAPIConnectionProperties

Methods:

  • GetConfigValue<T>(string key, T defaultValue) β€” Generic config value retrieval with caching
  • SetConfigValue(string key, object value) β€” Sets config and updates connection properties
  • GetHeaders() β€” Returns HTTP headers dict from config
  • GetEndpointConfiguration(string entityName) β€” Returns EndpointConfiguration (Get/Post/Put/Delete/List endpoints, method, auth, cache, rate limit)
  • GetAuthenticationConfiguration() β€” Returns the WebAPIConnectionProperties with auth settings
  • GetPaginationConfiguration() β€” Returns PaginationConfiguration (page/size/offset/limit param names, style)
  • ValidateConfiguration() β€” Returns ConfigurationValidationResult (BaseUrl, auth, timeout, retry, rate limit, pagination checks)

Nested types: EndpointConfiguration, ConfigurationValidationResult, PaginationConfiguration

WebAPIAuthenticationHelper

public class WebAPIAuthenticationHelper : IDisposable (239 lines)

Methods:

  • EnsureAuthenticatedAsync() β€” Validates auth state, triggers OAuth2 token refresh if needed
  • AddAuthenticationHeaders(HttpRequestMessage) β€” Injects auth headers: Bearer token, API Key (custom header name), Basic (base64 credentials)

Auth flow: Parses AuthType from Parameters string. Supports three OAuth2 grant types: client_credentials, password, authorization_code. Token caching with thread-safe refresh (_tokenLock + _tokenExpiry). Static bearer token fallback chain: KeyToken β†’ BearerToken β†’ ApiKey β†’ Parameters.

WebAPIRequestHelper

public class WebAPIRequestHelper : IDisposable (103 lines)

Methods:

  • SendWithRetryAsync(HttpRequestMessage, string? operationName) β€” Executes HTTP request with semaphore-based concurrency control, delegates retry/backoff to WebAPIErrorHelper
  • SendWithRetryAsync<T>(HttpRequestMessage, Func<HttpResponseMessage, Task<T>>, string? operationName) β€” Typed version with custom response handler

Behavior: Uses SemaphoreSlim(maxConcurrentRequests) for concurrency. Clones requests for retry safety via CloneHttpRequestMessageAsync (copies headers, content, version).

WebAPIDataHelper

public class WebAPIDataHelper (477 lines, no IDisposable)

URL building:

  • BuildEndpointUrl(baseUrl, endpoint, filters?, pageNumber?, pageSize?) β€” Full URL with query params
  • BuildEntityEndpoint(EntityStructure, filters?, pageNumber?, pageSize?) β€” Entity endpoint from structure
  • BuildEntityEndpoint(entityName, id) β€” Endpoint with ID path segment

Response parsing:

  • ProcessApiResponse(jsonResponse, entityStructure) β€” JSON to IEnumerable<object> (handles array, object, and nested data fields)
  • GetTotalRecordsFromResponse(jsonResponse, headers?) β€” Extracts total count from X-Total-Count header or JSON fields (total, totalCount, count, etc.)
  • ParseEntitiesFromDiscoveryResponse(jsonResponse) β€” Parses entity discovery JSON

Data utilities:

  • CreateRequest(method, endpoint, data?) β€” Creates HttpRequestMessage with camelCase JSON body
  • AddCustomHeaders(request, headers) β€” Adds custom headers (with content-header fallback)
  • ExtractIdValue(object data) β€” Extracts ID from common field names (id, Id, ID, _id, uuid, key)
  • InferEntityStructureFromSample(entityName, JsonElement) β€” Infers schema from sample data
  • GenerateCacheKey(baseKey, filters?, pageNumber, pageSize) β€” Cache key generation

WebAPICacheHelper

public class WebAPICacheHelper : IDisposable (203 lines)

Storage: ConcurrentDictionary<string, CacheEntry> with background cleanup timer (every 5 min).

Methods:

  • GenerateCacheKey(operation, params[]) β€” Key format: {datasource}:{operation}:{params}
  • Get<T>(cacheKey) β€” Retrieves cached value (null if expired/missing)
  • Set<T>(cacheKey, value, ttl?) β€” Stores with optional TTL (default from constructor)
  • Remove(cacheKey) β€” Removes specific entry
  • RemoveByPattern(pattern) β€” Removes entries matching substring
  • Clear() β€” Clears all entries
  • GetStatistics() β€” Returns CacheStatistics (total/valid/expired entries, efficiency %)
  • GetOrSetAsync<T>(cacheKey, factory, ttl?) β€” Get-or-set pattern with async factory

Nested type: CacheStatistics

WebAPIRateLimitHelper

public class WebAPIRateLimitHelper : IDisposable (293 lines)

Algorithm: Token bucket (per-endpoint buckets in ConcurrentDictionary). Background cleanup of stale buckets.

Properties: DefaultRequestsPerSecond (10), DefaultBurstCapacity (20), CleanupIntervalMinutes (5)

Methods:

  • WaitForPermissionAsync(endpoint, requestsPerSecond?, burstCapacity?, CancellationToken) β€” Waits until a token is available (delays if rate limited)
  • CanMakeRequest(endpoint, requestsPerSecond?, burstCapacity?) β€” Non-blocking check
  • GetStatus(endpoint) β€” Returns RateLimitStatus (tokens available, refill rate, next refill time)

Nested type: RateLimitStatus (Endpont, TokensAvailable, RefillRate, NextRefillTime)

WebAPISchemaHelper

public class WebAPISchemaHelper : IDisposable (621 lines)

Properties: SchemaCacheExpirationMinutes (60), MaxNestingDepth (5), MinSampleSize (3)

Methods:

  • InferEntityStructureAsync(entityName) β€” Auto-discovers schema by fetching sample data from entity endpoint
  • InferSchemaFromJsonAsync(entityName, jsonData, forceRefresh?) β€” Infers schema from JSON samples (up to 50)
  • ValidateSchemaAsync(EntityStructure, jsonData) β€” Validates schema against actual data (field existence, type consistency)
  • UpdateSchemaAsync(EntityStructure, jsonData) β€” Re-infers schema preserving existing field metadata (IsKey, IsUnique, etc.)
  • TryGetCachedSchema(entityName, out EntityStructure) β€” Cache lookup with expiration check
  • ClearCache() β€” Clears cached schemas

Nested type: SchemaValidationResult (EntityName, IsValid, Issues, SuggestedChanges)

WebAPIErrorHelper

public class WebAPIErrorHelper : IDisposable (634 lines)

Properties: DefaultMaxRetries (3), DefaultBaseDelayMs (1000), DefaultFailureThreshold (5), DefaultRecoveryTimeoutSeconds (60)

Methods:

  • ExecuteWithRetryAsync<T>(operation, operationName, maxRetries?, baseDelayMs?, CancellationToken) β€” Executes with exponential backoff + jitter, circuit breaker protection
  • HandleErrorResponseAsync(HttpResponseMessage) β€” Logs categorized error from HTTP response
  • CategorizeErrorAsync(HttpResponseMessage) β€” Returns WebApiError (status code, category, message, content, timestamp)
  • AnalyzeError(Exception) β€” Returns ErrorAnalysisResult with category, retryability, suggested action
  • GetCircuitBreakerStatus(operationName) β€” Returns current circuit breaker state
  • ResetCircuitBreaker(operationName) β€” Manually resets circuit breaker

Error categories: WebApiErrorCategory (ClientError, AuthenticationError, AuthorizationError, ServerError, NetworkError, Unknown), ErrorCategory (Network, Authentication, Configuration, Timeout, Logic, Unknown)

Circuit breaker states: Closed β†’ Open (after FailureThreshold failures) β†’ HalfOpen (after RecoveryTimeout) β†’ Closed (on success). Per-operation instances.

WebAPIInterfaces

File: WebAPIInterfaces.cs (35 lines)

IWebAPISchemaHelper (extends IDisposable):

  • DiscoverEntitiesAsync(HttpClient, ConnectionProperties) β€” Task<List<EntityStructure>>
  • InferEntityStructureAsync(entityName, HttpClient, ConnectionProperties) β€” Task<EntityStructure>
  • GetEntityType(entityName) β€” Type
  • ValidateEntityStructure(EntityStructure) β€” bool
  • EntityExistsAsync(entityName) β€” Task<bool>

IWebAPIDataHelper (extends IDisposable):

  • CreateDynamicType(entityName) β€” Type
  • ParseJsonToSingleObject(string) β€” object
  • ParseJsonToObjects(string) β€” List<object>
  • TransformToJsonString(object) β€” string
  • ValidateData(object, string) β€” DataValidationResult

DataValidationResult: IsValid (bool), Errors (List<string>)

Migration Guide

From Custom HTTP Clients

// Before: Manual HTTP client usage
using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
    var response = await client.GetAsync("https://api.example.com/users");
    var content = await response.Content.ReadAsStringAsync();
    // Manual JSON parsing and error handling...
}

// After: WebAPIDataSource usage
var users = webApiDS.GetEntity("Users", null);
// Automatic authentication, error handling, caching, and parsing

From Database DataSources

// Database-style operations work seamlessly
var filters = new List<AppFilter> {
    new AppFilter {FieldName = "status", FilterValue = "active", Operator = "=" }
};

var activeUsers = webApiDS.GetEntity("Users", filters); // Just like RDBSource!

// CRUD operations
webApiDS.InsertEntity("Users", newUser);
webApiDS.UpdateEntity("Users", updatedUser);
webApiDS.DeleteEntity("Users", userToDelete);

HTTP Convenience Methods

In addition to the IDataSource CRUD interface, WebAPIDataSource exposes low-level HTTP helpers defined in WebAPIDataSource.Http.cs. These are the preferred way to call API-specific endpoints that don't map cleanly to entity operations, and they are the building blocks used by connector subclasses.

GET — raw response or deserialized

// Raw HttpResponseMessage
HttpResponseMessage resp = await ds.GetAsync(
    "users/me",
    query: new Dictionary<string, string> { ["fields"] = "id,name,email" },
    headers: new Dictionary<string, string> { ["Accept-Language"] = "en" }
);

// Deserialize directly to T
var me = await ds.GetAsync<UserProfile>("users/me");
// Returns default(T) on failure β€” never throws

POST / PUT / DELETE

// POST with a body
await ds.PostAsync("tweets", body: new { text = "Hello from Beep!" });

// PUT (full replace)
await ds.PutAsync($"users/{userId}", body: updatedUser);

// DELETE
await ds.DeleteAsync($"tweets/{tweetId}");
Authentication and headers are applied automatically

All four methods call _authHelper.EnsureAuthenticatedAsync() and _authHelper.AddAuthenticationHeaders(request) before sending, and apply the default headers from WebAPIConnectionProperties. Retry logic is handled by WebAPIRequestHelper.SendWithRetryAsync.

Absolute vs relative URLs

If endpointOrUrl starts with http it is used as-is. Otherwise it is combined with _configHelper.BaseUrl (the ConnectionString value).

Building a Custom API Connector

The recommended way to integrate a specific REST API — Twitter, GitHub, Stripe, any social or SaaS platform — is to subclass WebAPIDataSource and override the methods that need API-specific URL or response handling. The TwitterDataSource is the canonical reference implementation.

Connector Pattern

Minimum viable connector skeleton

// 1. Annotate with [AddinAttribute] so AssemblyHandler registers it automatically
[AddinAttribute(
    Category = DatasourceCategory.Connector,
    DatasourceType = DataSourceType.Twitter  // use the correct enum value for your API
)]
public class MyApiDataSource : WebAPIDataSource
{
    // 2. Map logical entity names to API endpoint paths
    private static readonly Dictionary<string, string> EntityEndpoints
        = new(StringComparer.OrdinalIgnoreCase)
    {
        ["items.list"]   = "items",
        ["items.by_id"]  = "items/{id}",
        ["items.search"] = "items/search"
    };

    // 3. Declare which AppFilter keys are required for each entity
    private static readonly Dictionary<string, string[]> RequiredFilters
        = new(StringComparer.OrdinalIgnoreCase)
    {
        ["items.by_id"]  = new[] { "id" },
        ["items.search"] = new[] { "query" }
    };

    public MyApiDataSource(
        string datasourcename, IDMLogger logger,
        IDMEEditor dmeEditor, DataSourceType databasetype, IErrorsInfo errorObject)
        : base(datasourcename, logger, dmeEditor, databasetype, errorObject)
    {
        EntitiesNames = EntityEndpoints.Keys.ToList();
        Entities = EntitiesNames
            .Select(n => new EntityStructure { EntityName = n, DatasourceEntityName = n })
            .ToList();
    }

    // 4. Override GetEntityAsync to drive URL resolution and response extraction
    public override async Task<IEnumerable<object>> GetEntityAsync(
        string EntityName, List<AppFilter> Filter)
    {
        if (!EntityEndpoints.TryGetValue(EntityName, out var endpoint))
            throw new InvalidOperationException($"Unknown entity '{EntityName}'");

        var q = FiltersToQuery(Filter);
        RequireFilters(EntityName, q,
            RequiredFilters.GetValueOrDefault(EntityName, Array.Empty<string>()));

        var resolvedEndpoint = ResolveEndpoint(endpoint, q);
        using var resp = await GetAsync(resolvedEndpoint, q);
        if (resp is null || !resp.IsSuccessStatusCode) return Array.Empty<object>();

        return ExtractArray(resp, "data");  // key in JSON root where items live
    }

    // 5. Expose sync overload
    public override IEnumerable<object> GetEntity(string EntityName, List<AppFilter> filter)
        => GetEntityAsync(EntityName, filter).GetAwaiter().GetResult() ?? Array.Empty<object>();
}
Helper methods inherited from WebAPIDataSource
MethodWhat it does
FiltersToQuery(filters)Converts List<AppFilter> to Dictionary<string,string> query-string map
RequireFilters(name, q, keys)Throws if any mandatory keys are absent from the query map
ResolveEndpoint(template, q)Substitutes {param} placeholders from query map and removes consumed keys
ExtractArray(response, key)Reads the JSON body and returns List<object> from the named root key ("data", "results", etc.)
BuildUrlWithQuery(endpoint, q)Combines base URL, path, and remaining query-string params

Twitter: Connection Setup

TwitterDataSource targets the Twitter API v2 (https://api.twitter.com/2) with Bearer token auth. Set up the connection via WebAPIConnectionProperties or through ConfigEditor.AddDataConnection.

Register via ConfigEditor (recommended)

var conn = new WebAPIConnectionProperties
{
    ConnectionName   = "Twitter",
    ConnectionString = "https://api.twitter.com/2",
    DatabaseType     = DataSourceType.Twitter,
    Category         = DatasourceCategory.Connector,
    DriverName       = "TwitterDataSource",       // matches [AddinAttribute]

    // Authentication
    ApiKey           = "AAAA...",                 // Bearer token
    // Store auth type in Parameters (read by WebAPIAuthenticationHelper)
};
// Set bearer auth type in extra Parameters
conn.Parameters = "AuthType=Bearer";

// Add a default Authorization header directly (simplest approach)
conn.Headers.Add(new WebApiHeader
{
    Key   = "Authorization",
    Value = $"Bearer {bearerToken}"
});

dmeEditor.ConfigEditor.AddDataConnection(conn);

// Get the data source (AssemblyHandler resolves TwitterDataSource via [AddinAttribute])
var twitter = (TwitterDataSource)dmeEditor.GetDataSource("Twitter");
twitter.Openconnection();
Do not hardcode secrets

Load your Bearer token from environment variables or a secrets manager. Never commit tokens to version control.

Twitter: Entities & Filters

TwitterDataSource registers 10 logical entity names that map to Twitter API v2 endpoints. Each entity declares which AppFilter.FieldName keys are required.

Entity → Endpoint mapping
Entity nameTwitter API v2 pathRequired filters
tweets.searchtweets/search/recentquery
tweets.by_idtweetsids
users.by_usernameusers/byusernames
users.by_idusersids
users.tweetsusers/{id}/tweetsid
users.followersusers/{id}/followersid
users.followingusers/{id}/followingid
lists.by_userusers/{id}/owned_listsid
lists.tweetslists/{id}/tweetsid
spaces.searchspaces/searchquery
AppFilter → query-string mapping

FiltersToQuery converts each AppFilter to a key=value query-string entry using AppFilter.FieldName as the key and AppFilter.FilterValue as the value. Endpoint path parameters (e.g., {id}) are consumed by ResolveEndpoint and removed from the query string.

Twitter: Reading Data

Search recent tweets (IDataSource style)

var filters = new List<AppFilter>
{
    new AppFilter { FieldName = "query",       FilterValue = "BeepDM",  Operator = "=" },
    new AppFilter { FieldName = "max_results", FilterValue = "20",      Operator = "=" }
};

var raw = twitter.GetEntity("tweets.search", filters);
// Returns IEnumerable<object> (each item is a deserialized JSON object)

Get user's followers

var filters = new List<AppFilter>
{
    new AppFilter { FieldName = "id", FilterValue = "12345678", Operator = "=" }
};

var followers = twitter.GetEntity("users.followers", filters);

Get tweets for a list

var filters = new List<AppFilter>
{
    new AppFilter { FieldName = "id", FilterValue = "listId123", Operator = "=" },
    new AppFilter { FieldName = "max_results", FilterValue = "50", Operator = "=" }
};

var tweets = twitter.GetEntity("lists.tweets", filters);

Twitter: Typed [CommandAttribute] Methods

TwitterDataSource exposes strongly-typed methods decorated with [CommandAttribute]. These are discovered by the Beep UI and tooling to build call panels automatically.

Search tweets — typed

// Returns IEnumerable<TwitterTweet> (from Models.cs)
IEnumerable<TwitterTweet> tweets = await twitter.GetTweets(
    query: "#dotnet lang:en",
    maxResults: 25
);

foreach (var tweet in tweets)
{
    Console.WriteLine($"{tweet.CreatedAt:s}  @{tweet.AuthorId}");
    Console.WriteLine($"  {tweet.Text}");
    Console.WriteLine($"  Likes: {tweet.PublicMetrics?.LikeCount}  " +
                      $"RT: {tweet.PublicMetrics?.RetweetCount}");
}

User timeline

var timeline = await twitter.GetUserTimeline(
    userId: "12345678",
    maxResults: 50
);

var popular = timeline
    .OrderByDescending(t => t.PublicMetrics?.LikeCount ?? 0)
    .Take(5);

foreach (var t in popular)
    Console.WriteLine($"{t.PublicMetrics?.LikeCount,6} likes — {t.Text[..50]}");

User lookup

// By username
var users = await twitter.GetUserByUsername("beep_dm");
var user  = users.FirstOrDefault();
Console.WriteLine($"{user?.Name} — {user?.PublicMetrics?.FollowersCount} followers");

// By ID
var byId = await twitter.GetUserById("12345678");
Available typed methods
MethodReturnsRequired params
GetTweets(query, maxResults, nextToken?)IEnumerable<TwitterTweet>query
GetUserTimeline(userId, maxResults, nextToken?)IEnumerable<TwitterTweet>userId
GetUserByUsername(username)IEnumerable<TwitterUser>username
GetUserById(userId)IEnumerable<TwitterUser>userId

Twitter: Cursor Pagination

Twitter API v2 uses cursor-based pagination via meta.next_token. TwitterDataSource.GetEntity(name, filter, pageNumber, pageSize) emulates page-number semantics by walking the cursor chain up to pageNumber pages, then returns the requested page.

Paged retrieval (IDataSource PagedResult)

var filters = new List<AppFilter>
{
    new AppFilter { FieldName = "query", FilterValue = "#csharp", Operator = "=" }
};

// Page 1 (first 20 results)
PagedResult page1 = twitter.GetEntity("tweets.search", filters, pageNumber: 1, pageSize: 20);
Console.WriteLine($"Page 1: {page1.Data.Count} items");
Console.WriteLine($"Has next: {page1.HasNextPage}");

// Page 2
PagedResult page2 = twitter.GetEntity("tweets.search", filters, pageNumber: 2, pageSize: 20);

Explicit cursor pass-through (typed method)

string? cursor = null;
do
{
    var batch = await twitter.GetTweets("#dotnet", maxResults: 100, nextToken: cursor);
    ProcessBatch(batch);

    // Extract next_token from the last raw page for the next call
    // (use typed method overload or inspect PagedResult.TotalPages instead)
    cursor = GetNextCursor(batch); // your own helper to read meta.next_token
}
while (cursor != null);
Rate limits

Twitter API v2 Free tier: 500,000 tweet reads / month; 1 app / 1 user. Basic tier: 10,000 tweet reads / month with higher rate ceilings. Use WebAPIConnectionProperties.EnableRateLimit = true and RateLimitRequestsPerMinute to throttle automatically.

Connector Checklist

Follow these steps when building any new WebAPIDataSource subclass:

  1. Add [AddinAttribute(Category = DatasourceCategory.Connector, DatasourceType = DataSourceType.YourType)].
  2. Define EntityEndpoints (entity name → URL template dictionary).
  3. Define RequiredFilters (entity name → required AppFilter.FieldName array).
  4. Populate EntitiesNames and Entities in the constructor.
  5. Override GetEntityAsync: call FiltersToQuery → RequireFilters → ResolveEndpoint → GetAsync → ExtractArray.
  6. Add sync GetEntity override that delegates to GetEntityAsync(...).GetAwaiter().GetResult().
  7. Optionally override GetEntity (paged) for cursor or offset pagination.
  8. Add typed [CommandAttribute] methods for Beep tooling discoverability.
  9. Create a Models.cs with JSON-annotated POCOs for response deserialization.
  10. Store the connector in BeepDataSources/Connectors/<Category>/<Name>/.