Proxy API Service

Overview

The Proxy API Service serves as an intermediary API layer that exposes two primary functionalities:

This service abstracts and consolidates multiple external API interactions behind a single, consistent RESTful interface, simplifying client integration and enhancing security and performance through caching and controlled access.


Purpose and Problem Solved

Blockchain applications require reliable address validation to prevent fraudulent or risky transactions and often need to fetch market data, portfolio information, or liquidity quotes from various external services. Direct client integration with these external APIs can be complex due to:

The Proxy API Service addresses these problems by:


Core Functionalities and Workflows

1. Address Validation

Example usage snippet from the controller:

@Route('api/v1')
export class Proxy extends Controller {
  @Get('/validate/{address}')
  async validateAddress(@Path() address: string): Promise<ValidationResult> {
    return await elliptic.validateAddress(address)
  }
}

2. External API Proxying

The service proxies requests to external APIs under predefined paths, forwarding incoming requests while managing authentication and caching.

Example proxy handler usage in `app.ts`:

const coingecko = new CoinGecko()
app.get('/api/v1/markets/*', coingecko.handler.bind(coingecko))

const zerion = new Zerion()
app.get('/api/v1/zerion/*', zerion.handler.bind(zerion))

const zrx = new Zrx()
app.get('/api/v1/zrx/*', zrx.handler.bind(zrx))

Module Structure and File Interactions

The interaction between these files is coordinated by the Express app (`app.ts`), which routes requests to the appropriate handlers. The proxy clients handle forwarding and caching transparently.


Important Concepts and Design Patterns

Caching Strategy

Error Handling and Fallbacks

API Gateway Pattern

Dependency Injection and Binding


Example Code Snippets Illustrating Key Concepts

Address Validation Method (Caching & Risk Assessment)

async validateAddress(address: string): Promise<{ valid: boolean }> {
  const cached = this.addressCache[address]
  if (cached !== undefined) return { valid: cached }

  try {
    const { data } = await this.aml.client.post('/v2/wallet/synchronous', { ... })

    if (data.risk_score && data.risk_score >= RISK_SCORE_THRESHOLD) {
      this.addressCache[address] = false
      return { valid: false }
    }

    this.addressCache[address] = true
    return { valid: true }
  } catch (err) {
    if (/* err indicates not in blockchain */) {
      this.addressCache[address] = true
      return { valid: true }
    }
    throw err
  } finally {
    if (this.addressCache[address] === true) {
      setInterval(() => delete this.addressCache[address], CACHE_TTL_MS)
    }
  }
}

External API Proxy Handler (CoinGecko Example)

async handler(req: Request, res: Response): Promise<void> {
  const cachedResponse = this.requestCache[req.url]
  if (cachedResponse) {
    res.set('X-Cache', 'HIT')
    res.status(cachedResponse.status).send(cachedResponse.data)
    return
  }

  res.set('X-Cache', 'MISS')

  try {
    const response = await this.axiosInstance.get(`${BASE_URL}${url}`)
    this.requestCache[req.url] = response
    res.status(response.status).send(response.data)
  } catch (err) {
    // Forward error status and message
  } finally {
    setInterval(() => delete this.requestCache[req.url], CACHE_TTL_MS)
  }
}

Interaction Flow Diagram

This flowchart illustrates how an incoming API request is processed by the Proxy API Service, highlighting the decision points for address validation and external API proxying, including caching and error handling.

flowchart TD
  ClientRequest[Client sends API request] --> ParseURL{Request Path}
  
  ParseURL -->|Validate Address| ValidateAddr[Address Validation Controller]
  ParseURL -->|CoinGecko Proxy| CoinGeckoProxy[CoinGecko Proxy Handler]
  ParseURL -->|Zerion Proxy| ZerionProxy[Zerion Proxy Handler]
  ParseURL -->|0x Proxy| ZrxProxy[0x Proxy Handler]
  ParseURL -->|Other| DocsRedirect[Redirect to API Docs]

  %% Address Validation Flow
  ValidateAddr --> CheckCacheAddr{Is address in cache?}
  CheckCacheAddr -->|Yes| ReturnCachedAddr[Return cached validation result]
  CheckCacheAddr -->|No| CallElliptic[Call Elliptic AML API]
  CallElliptic --> AssessRisk{Risk score >= threshold?}
  AssessRisk -->|Yes| ReturnInvalid[Return invalid result]
  AssessRisk -->|No| CacheValid[Cache valid result]
  CacheValid --> ReturnValid[Return valid result]

  %% Proxy Flow (shared)
  CoinGeckoProxy --> CheckCacheProxyCG{Is request cached?}
  ZerionProxy --> CheckCacheProxyZerion{Is request cached?}
  ZrxProxy --> CheckCacheProxyZrx{Is request cached?}

  CheckCacheProxyCG -->|Yes| ReturnCacheCG[Return cached response]
  CheckCacheProxyCG -->|No| ForwardCG[Forward request to CoinGecko API]
  ForwardCG --> CacheCG[Cache response]
  CacheCG --> ReturnResponseCG[Return API response]

  CheckCacheProxyZerion -->|Yes| ReturnCacheZerion[Return cached response]
  CheckCacheProxyZerion -->|No| ForwardZerion[Forward request to Zerion API]
  ForwardZerion --> CacheZerion[Cache response]
  CacheZerion --> ReturnResponseZerion[Return API response]

  CheckCacheProxyZrx -->|Yes| ReturnCacheZrx[Return cached response]
  CheckCacheProxyZrx -->|No| ForwardZrx[Forward request to 0x API]
  ForwardZrx --> ReturnResponseZrx[Return API response]

  DocsRedirect --> ServeDocs[Serve API documentation]

  %% Error handling implicit in each step

This documentation page outlines the Proxy API Service's role as a centralized validation and proxy layer, detailing its workflow, caching strategies, and integration with third-party APIs. The service enhances client usability and system security by managing API keys, caching, and error propagation internally.