Skip to content

Latest commit

 

History

History
788 lines (590 loc) · 15.3 KB

File metadata and controls

788 lines (590 loc) · 15.3 KB

📡 API Reference

Complete API documentation for the Ethereum RPC Load Balancer.


Table of Contents


Public Endpoints (Port 8080)

These endpoints are publicly accessible and do not require authentication.

JSON-RPC Proxy

The main proxy endpoint that forwards JSON-RPC requests to backend Ethereum providers.

Endpoint: POST /

Headers:

Content-Type: application/json

Request Body:

{
  "jsonrpc": "2.0",
  "method": "eth_blockNumber",
  "params": [],
  "id": 1
}

Response (200 OK):

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x12a4b7c"
}

Supported Methods:

  • eth_blockNumber - Get latest block number
  • eth_getBlockByNumber - Get block by number (cacheable)
  • eth_getBlockByHash - Get block by hash (cacheable)
  • eth_getTransactionByHash - Get transaction by hash (cacheable)
  • eth_getTransactionReceipt - Get transaction receipt (cacheable)
  • eth_call - Execute call (not cacheable)
  • eth_estimateGas - Estimate gas (not cacheable)
  • eth_gasPrice - Get current gas price (not cacheable)
  • eth_getBalance - Get account balance
  • eth_getCode - Get contract code
  • eth_getLogs - Get event logs
  • And all other standard Ethereum JSON-RPC methods

Caching Behavior:

  • Requests with "latest" parameter are never cached
  • Finalized blocks (>64 blocks old) are cached indefinitely
  • Recent blocks (within 64 blocks) are cached for 5 minutes
  • Unfinalized blocks are cached for 30 seconds

Error Responses:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "All providers are currently unavailable"
  }
}

Provider Statistics (Read-Only)

Get statistics about all configured providers.

Endpoint: GET /providers

Response (200 OK):

{
  "providers": [
    {
      "id": "infura",
      "url": "https://mainnet.infura.io/v3/YOUR_KEY",
      "healthy": true,
      "weight": 85.2,
      "requestCount": 1523,
      "errorCount": 3,
      "avgLatencyMs": 142,
      "lastHealthCheck": "2025-10-14T10:29:45Z",
      "circuitBreakerState": "closed"
    },
    {
      "id": "alchemy",
      "url": "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
      "healthy": true,
      "weight": 92.8,
      "requestCount": 1687,
      "errorCount": 1,
      "avgLatencyMs": 128,
      "lastHealthCheck": "2025-10-14T10:29:45Z",
      "circuitBreakerState": "closed"
    }
  ],
  "totalProviders": 2,
  "healthyProviders": 2,
  "routingStrategy": "weighted"
}

Response Fields:

  • id - Provider identifier
  • url - RPC endpoint URL (API keys masked)
  • healthy - Current health status
  • weight - Current routing weight (higher = more traffic)
  • requestCount - Total requests sent to this provider
  • errorCount - Total error count
  • avgLatencyMs - Average response time in milliseconds
  • lastHealthCheck - Timestamp of last health check
  • circuitBreakerState - Circuit breaker state: closed (healthy), open (failing), half-open (testing)

Health Check

Quick health status of the load balancer.

Endpoint: GET /health

Response (200 OK):

{
  "status": "healthy",
  "timestamp": "2025-10-14T10:30:00Z",
  "activeProviders": 2,
  "totalProviders": 2
}

Response (503 Service Unavailable) - when all providers are down:

{
  "status": "unhealthy",
  "timestamp": "2025-10-14T10:30:00Z",
  "activeProviders": 0,
  "totalProviders": 2,
  "reason": "No healthy providers available"
}

Detailed Health

Comprehensive health information including Redis connectivity and provider details.

Endpoint: GET /health/detailed

Response (200 OK):

{
  "status": "healthy",
  "timestamp": "2025-10-14T10:30:00Z",
  "providers": {
    "total": 2,
    "healthy": 2,
    "unhealthy": 0,
    "details": [
      {
        "id": "infura",
        "healthy": true,
        "latencyMs": 142,
        "circuitBreakerState": "closed"
      },
      {
        "id": "alchemy",
        "healthy": true,
        "latencyMs": 128,
        "circuitBreakerState": "closed"
      }
    ]
  },
  "cache": {
    "connected": true,
    "hitRate": 0.73,
    "keyCount": 45231
  },
  "uptime": 3600
}

Prometheus Metrics

Raw Prometheus metrics for scraping.

Endpoint: GET /metrics

Response (200 OK):

# HELP rpc_lb_requests_total Total RPC requests by provider
# TYPE rpc_lb_requests_total counter
rpc_lb_requests_total{provider="infura",method="eth_blockNumber"} 1523

# HELP rpc_lb_request_duration_seconds RPC request duration
# TYPE rpc_lb_request_duration_seconds histogram
rpc_lb_request_duration_seconds_bucket{provider="infura",le="0.1"} 1200
rpc_lb_request_duration_seconds_bucket{provider="infura",le="0.5"} 1500

# HELP rpc_lb_cache_hits_total Cache hits by method
# TYPE rpc_lb_cache_hits_total counter
rpc_lb_cache_hits_total{method="eth_getBlockByNumber"} 3421

# HELP rpc_lb_provider_health Provider health status (1=healthy, 0=unhealthy)
# TYPE rpc_lb_provider_health gauge
rpc_lb_provider_health{provider="infura"} 1

Admin Endpoints (Port 8081)

Administrative endpoints for managing providers and cache. Requires authentication.

Authentication

All admin endpoints require HTTP Basic Authentication.

Headers:

Authorization: Basic YWRtaW46Y2hhbmdlbWU=

Or using curl:

curl -u admin:changeme http://localhost:8081/admin/providers

Default Credentials:

  • Username: admin
  • Password: changeme (change via ADMIN_PASSWORD environment variable)

Error Response (401 Unauthorized):

{
  "error": "Authentication required"
}

View All Providers

Get detailed information about all configured providers.

Endpoint: GET /admin/providers

Authentication: Required (Basic Auth)

Response (200 OK):

{
  "providers": [
    {
      "id": "infura",
      "url": "https://mainnet.infura.io/v3/YOUR_KEY",
      "healthy": true,
      "weight": 85.2,
      "requestCount": 1523,
      "errorCount": 3,
      "avgLatencyMs": 142,
      "successRate": 0.998,
      "lastHealthCheck": "2025-10-14T10:29:45Z",
      "circuitBreakerState": "closed",
      "circuitBreakerStats": {
        "failures": 0,
        "lastFailureTime": null,
        "nextRetryTime": null
      }
    }
  ],
  "summary": {
    "totalProviders": 2,
    "healthyProviders": 2,
    "totalRequests": 3210,
    "totalErrors": 4,
    "avgLatencyMs": 135
  }
}

View Specific Provider

Get detailed information about a single provider.

Endpoint: GET /admin/providers/:id

Authentication: Required (Basic Auth)

Path Parameters:

  • id - Provider identifier (e.g., infura)

Example:

curl -u admin:changeme http://localhost:8081/admin/providers/infura

Response (200 OK):

{
  "id": "infura",
  "url": "https://mainnet.infura.io/v3/YOUR_KEY",
  "healthy": true,
  "weight": 85.2,
  "requestCount": 1523,
  "errorCount": 3,
  "avgLatencyMs": 142,
  "successRate": 0.998,
  "lastHealthCheck": "2025-10-14T10:29:45Z",
  "circuitBreakerState": "closed",
  "circuitBreakerStats": {
    "failures": 0,
    "lastFailureTime": null,
    "nextRetryTime": null
  },
  "recentRequests": [
    {
      "method": "eth_blockNumber",
      "latencyMs": 145,
      "success": true,
      "timestamp": "2025-10-14T10:29:45Z"
    }
  ]
}

Error Response (404 Not Found):

{
  "error": "Provider not found",
  "providerId": "unknown"
}

Add Provider

Add a new RPC provider to the pool.

Endpoint: POST /admin/providers

Authentication: Required (Basic Auth)

Headers:

Content-Type: application/json

Request Body:

{
  "id": "quicknode",
  "url": "https://ethereum.quicknode.com/YOUR_KEY",
  "weight": 1,
  "priority": 1
}

Request Fields:

  • id (required) - Unique identifier for the provider
  • url (required) - RPC endpoint URL
  • weight (optional) - Initial weight, default: 1
  • priority (optional) - Provider priority, default: 1

Example:

curl -u admin:changeme -X POST http://localhost:8081/admin/providers \
  -H "Content-Type: application/json" \
  -d '{
    "id": "quicknode",
    "url": "https://ethereum.quicknode.com/YOUR_KEY",
    "weight": 1
  }'

Response (201 Created):

{
  "success": true,
  "message": "Provider added successfully",
  "provider": {
    "id": "quicknode",
    "url": "https://ethereum.quicknode.com/YOUR_KEY",
    "healthy": false,
    "weight": 1,
    "requestCount": 0,
    "errorCount": 0
  }
}

Error Response (400 Bad Request):

{
  "error": "Provider with this ID already exists"
}

Update Provider

Update provider configuration (weight, health status).

Endpoint: PATCH /admin/providers/:id

Authentication: Required (Basic Auth)

Path Parameters:

  • id - Provider identifier

Headers:

Content-Type: application/json

Request Body (all fields optional):

{
  "weight": 2,
  "healthy": false
}

Example:

# Update weight
curl -u admin:changeme -X PATCH http://localhost:8081/admin/providers/infura \
  -H "Content-Type: application/json" \
  -d '{"weight": 2}'

# Force disable provider
curl -u admin:changeme -X PATCH http://localhost:8081/admin/providers/infura \
  -H "Content-Type: application/json" \
  -d '{"healthy": false}'

Response (200 OK):

{
  "success": true,
  "message": "Provider updated successfully",
  "provider": {
    "id": "infura",
    "weight": 2,
    "healthy": false
  }
}

Remove Provider

Remove a provider from the pool.

Endpoint: DELETE /admin/providers/:id

Authentication: Required (Basic Auth)

Path Parameters:

  • id - Provider identifier

Example:

curl -u admin:changeme -X DELETE http://localhost:8081/admin/providers/infura

Response (200 OK):

{
  "success": true,
  "message": "Provider removed successfully",
  "providerId": "infura"
}

Error Response (404 Not Found):

{
  "error": "Provider not found"
}

Force Enable Provider

Force-enable a provider, overriding circuit breaker state.

Endpoint: POST /admin/providers/:id/enable

Authentication: Required (Basic Auth)

Path Parameters:

  • id - Provider identifier

Example:

curl -u admin:changeme -X POST http://localhost:8081/admin/providers/infura/enable

Response (200 OK):

{
  "success": true,
  "message": "Provider enabled successfully",
  "provider": {
    "id": "infura",
    "healthy": true,
    "circuitBreakerState": "closed"
  }
}

Force Disable Provider

Force-disable a provider, preventing it from receiving traffic.

Endpoint: POST /admin/providers/:id/disable

Authentication: Required (Basic Auth)

Path Parameters:

  • id - Provider identifier

Example:

curl -u admin:changeme -X POST http://localhost:8081/admin/providers/infura/disable

Response (200 OK):

{
  "success": true,
  "message": "Provider disabled successfully",
  "provider": {
    "id": "infura",
    "healthy": false,
    "circuitBreakerState": "open"
  }
}

Cache Statistics

Get detailed cache statistics.

Endpoint: GET /admin/cache/stats

Authentication: Required (Basic Auth)

Example:

curl -u admin:changeme http://localhost:8081/admin/cache/stats

Response (200 OK):

{
  "connected": true,
  "totalKeys": 45231,
  "hitRate": 0.73,
  "missRate": 0.27,
  "hits": 12543,
  "misses": 4621,
  "memoryUsage": {
    "used": "52.4 MB",
    "peak": "68.2 MB"
  },
  "keysByMethod": {
    "eth_getBlockByNumber": 32145,
    "eth_getTransactionByHash": 8234,
    "eth_getBlockByHash": 3456,
    "eth_getTransactionReceipt": 1396
  },
  "ttlDistribution": {
    "infinite": 30124,
    "5min": 12345,
    "30sec": 2762
  }
}

Clear Cache

Clear cache entries by scope.

Endpoint: DELETE /admin/cache

Authentication: Required (Basic Auth)

Headers:

Content-Type: application/json

Request Body:

{
  "scope": "all" | "provider" | "pattern",
  "providerId": "infura",
  "pattern": "eth_getBlock*"
}

Request Fields:

  • scope (required) - Cache clearing scope:
    • all - Clear entire cache
    • provider - Clear cache for specific provider (requires providerId)
    • pattern - Clear cache matching pattern (requires pattern)
  • providerId (conditional) - Provider ID when scope=provider
  • pattern (conditional) - Glob pattern when scope=pattern

Examples:

# Clear entire cache
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
  -H "Content-Type: application/json" \
  -d '{"scope": "all"}'

# Clear cache for specific provider
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
  -H "Content-Type: application/json" \
  -d '{"scope": "provider", "providerId": "infura"}'

# Clear cache by pattern
curl -u admin:changeme -X DELETE http://localhost:8081/admin/cache \
  -H "Content-Type: application/json" \
  -d '{"scope": "pattern", "pattern": "eth_getBlock*"}'

Response (200 OK):

{
  "success": true,
  "message": "Cache cleared successfully",
  "keysDeleted": 15423,
  "scope": "all"
}

Error Codes

HTTP Status Codes

  • 200 OK - Request succeeded
  • 201 Created - Resource created successfully
  • 400 Bad Request - Invalid request body or parameters
  • 401 Unauthorized - Authentication required or invalid credentials
  • 404 Not Found - Resource not found
  • 500 Internal Server Error - Server error
  • 503 Service Unavailable - All providers unavailable

JSON-RPC Error Codes

Following the JSON-RPC 2.0 specification:

  • -32700 - Parse error
  • -32600 - Invalid request
  • -32601 - Method not found
  • -32602 - Invalid params
  • -32603 - Internal error (provider failures)
  • -32000 to -32099 - Server error (custom)

Rate Limiting

Currently, there is no rate limiting on the public API. For production deployments, consider:

  • Adding rate limiting middleware (e.g., express-rate-limit)
  • Implementing API key-based rate limiting
  • Using a reverse proxy with rate limiting (e.g., Nginx, Cloudflare)

CORS

CORS is enabled by default for all origins. To restrict origins, set the CORS_ORIGIN environment variable:

CORS_ORIGIN=https://yourdapp.com

Need Help?