Proxy API Service
Overview
The Proxy API Service serves as an intermediary API layer that exposes two primary functionalities:
Address Validation: Verifying the validity and risk exposure of blockchain addresses using a third-party AML (Anti-Money Laundering) provider.
External API Proxying: Forwarding client requests to external APIs such as Elliptic, CoinGecko, Zerion, and 0x, while adding caching, authentication, and unified access to these services.
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:
Varying authentication methods and API interfaces.
Rate limits and performance bottlenecks.
Security risks exposing API keys directly to clients.
Redundant data fetching and inconsistent caching strategies.
The Proxy API Service addresses these problems by:
Providing a centralized, authenticated API endpoint to validate blockchain addresses.
Acting as a proxy for external APIs, managing authentication headers and request forwarding.
Implementing response caching to reduce redundant external API calls and improve performance.
Offering a unified API interface with consistent error handling and status codes.
Core Functionalities and Workflows
1. Address Validation
What it Does: Validates a blockchain address by querying the Elliptic AML API to assess its risk exposure.
How it Works:
When a client calls the /api/v1/validate/{address} endpoint, the service uses the
Ellipticclass to validate the address.The service sends a synchronous wallet exposure request to Elliptic's API, specifying the address to check.
If the address has a risk score above a configured threshold, it is marked invalid.
If the address is not found in Elliptic's database (HTTP 404 with
NotInBlockchain), it is assumed valid, delegating responsibility back to the client.Results are cached in-memory for 6 hours to minimize repeated calls for the same address.
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.
Supported External APIs:
CoinGecko: Market data proxy under
/api/v1/markets/*.Zerion: Portfolio and token data proxy under
/api/v1/zerion/*.0x (Zrx): Liquidity and swap quotes proxy under
/api/v1/zrx/*.
Proxy Workflow:
The service extracts the relevant sub-path from the incoming request URL.
It checks an in-memory cache for a previous response to the same request.
On a cache hit, it immediately returns the cached data with an
X-Cache: HITheader.On a cache miss, it forwards the request to the external API using an authenticated HTTP client.
Response headers and status codes from the external API are preserved and forwarded to the client.
Responses are cached in-memory for a short TTL (typically 60 seconds) to reduce external API calls.
Authentication:
Each proxied API client is initialized with the respective API key loaded from environment variables.
The service automatically attaches appropriate headers (
x-cg-pro-api-key,Authorization,0x-api-key) to outgoing requests.
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
app.ts
Entry point that sets up the Express server, registers middleware, routes, and external API proxy handlers. It also serves API documentation and static assets.controller.ts
Defines theProxycontroller that exposes the address validation endpoint. It leverages theEllipticclass to perform validation logic.elliptic.ts
Implements the address validation logic by interacting with the Elliptic AML API. It includes caching and error handling specific to the AML provider.coingecko.ts
Implements a proxy client for CoinGecko’s API, including request caching and forwarding with API key authentication.zerion.ts
Implements a proxy client for Zerion’s API with similar caching and authentication handling.zrx.ts
Implements a proxy client for the 0x API. It has additional logic to dynamically select the correct 0x sub-API URL based on the blockchain network indicated in the request path.
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
The service uses in-memory caching with a TTL to reduce redundant external API calls and improve response times.
Cache keys are the full request URLs, ensuring distinct cache entries per unique request.
Cached responses include both data and headers, preserving API semantics.
TTL values differ by service (e.g., 60 seconds for market data, 6 hours for address validation).
Error Handling and Fallbacks
The address validation gracefully handles the case where the address is unknown to Elliptic by assuming validity, which prevents unnecessary blocking.
Proxy handlers catch HTTP errors and respond with appropriate status codes and messages forwarded from the external APIs, maintaining transparency.
Unexpected errors return a generic 500 Internal Server Error.
API Gateway Pattern
The Proxy API Service acts as an API gateway, centralizing access to multiple external services and providing a unified client interface.
This abstraction simplifies client-side integration by hiding the complexity of multiple third-party APIs and their authentication requirements.
Dependency Injection and Binding
Proxy handler methods are bound to class instances in
app.tsto maintain context (this) when used as Express route handlers.
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.