Skip to main content

SDK Generation Guide

Supported Languages: TypeScript, Python, Java, Go, Ruby, PHP Generation Tool: OpenAPI Generator CLI OpenAPI Version: 3.0.3 Last Generated: 2024-01-15

Table of Contents

  1. Overview
  2. Prerequisites
  3. Quick Start
  4. Language-Specific Guides
  5. Customization
  6. Testing
  7. CI/CD Integration
  8. Troubleshooting

Overview

What are Generated SDKs?

Generated SDKs (Software Development Kits) are client libraries automatically created from our OpenAPI specification. They provide:

  • Type Safety: Full type definitions for requests and responses
  • Auto-Completion: IDE support with intelligent code completion
  • Consistency: Guaranteed compatibility with the API specification
  • Documentation: Inline documentation from OpenAPI descriptions
  • Error Handling: Structured error handling and retry logic
  • Authentication: Built-in authentication mechanisms

Why Use Generated SDKs?

Benefits:

  • Reduce integration time from days to hours
  • Eliminate manual API client code
  • Automatic updates when API changes
  • Consistent patterns across languages
  • Built-in best practices

Supported Languages:

  • TypeScript/JavaScript (Node.js, Browser)
  • Python (3.7+)
  • Java (8+)
  • Go (1.18+)
  • Ruby (2.7+)
  • PHP (7.4+)

Prerequisites

Required Tools

  1. OpenAPI Generator CLI

    # Via npm
    npm install -g @openapitools/openapi-generator-cli

    # Via Homebrew (macOS)
    brew install openapi-generator

    # Via Docker
    docker pull openapitools/openapi-generator-cli
  2. Language-Specific Tools:

    • TypeScript: Node.js 16+, npm/yarn
    • Python: Python 3.7+, pip
    • Java: JDK 8+, Maven/Gradle
    • Go: Go 1.18+
    • Ruby: Ruby 2.7+, Bundler
    • PHP: PHP 7.4+, Composer

OpenAPI Specification

Ensure you have the OpenAPI specification file:

# Download the latest spec
curl -O https://api.tvl.com/openapi.yaml

# Or use from repository
git clone https://github.com/tvl/api-specs.git
cd api-specs

Quick Start

Generate Your First SDK

Step 1: Install the generator

npm install -g @openapitools/openapi-generator-cli

Step 2: Generate TypeScript SDK

./scripts/generate-sdk.sh typescript

Step 3: Use in your project

import { TvlSdk } from '@tvl/sdk';

const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key'
});

const protocols = await sdk.protocols.getProtocols();
console.log(protocols.data);

One-Command Generation

Generate all SDKs at once:

./scripts/generate-sdk.sh --all

Generate specific language:

./scripts/generate-sdk.sh python -o ./my-sdk

Language-Specific Guides

TypeScript/JavaScript

Generation

# Using the provided script
./scripts/generate-typescript-sdk.sh ./sdk-output

# Or using openapi-generator directly
openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-axios \
-o ./typescript-sdk \
--additional-properties=npmName=@tvl/sdk,supportsES6=true

Configuration Options

# Environment variables
export PACKAGE_NAME="@myorg/tvl-sdk"
export PACKAGE_VERSION="1.0.0"
export OPENAPI_SPEC="./custom-spec.yaml"

./scripts/generate-typescript-sdk.sh

Installation & Usage

Install:

cd typescript-sdk
npm install
npm run build

Usage:

import { TvlSdk } from '@tvl/sdk';

// Initialize
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: process.env.TVL_API_KEY,
timeout: 30000,
retryAttempts: 3
});

// Use the SDK
async function getProtocols() {
try {
const response = await sdk.protocols.getProtocols();
return response.data;
} catch (error) {
console.error('API Error:', error.message);
throw error;
}
}

Advanced Configuration

Custom Interceptors:

const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key',
onRequest: (config) => {
console.log('Request:', config.url);
config.headers['X-Custom-Header'] = 'value';
return config;
},
onResponse: (response) => {
console.log('Response:', response.status);
return response;
},
onError: (error) => {
console.error('Error:', error);
// Custom error handling (e.g., send to monitoring)
}
});

Authentication:

// API Key authentication
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key'
});

// Update API key at runtime
sdk.updateConfig({ apiKey: 'new-api-key' });

Error Handling:

import { TvlSdk } from '@tvl/sdk';

const sdk = new TvlSdk({ apiKey: 'your-api-key' });

try {
const protocol = await sdk.protocols.getProtocolById({ id: 'uniswap' });
} catch (error) {
if (error.status === 404) {
console.log('Protocol not found');
} else if (error.status === 429) {
console.log('Rate limit exceeded');
} else {
console.error('Unexpected error:', error);
}
}

Type Safety

import { TvlSdk, Protocol, ProtocolTvlHistory } from '@tvl/sdk';

const sdk = new TvlSdk({ apiKey: 'your-api-key' });

// Type-safe responses
const protocol: Protocol = await sdk.protocols.getProtocolById({
id: 'uniswap'
});

// Type-safe requests
const history: ProtocolTvlHistory[] = await sdk.protocols.getProtocolTvlHistory({
id: 'uniswap',
startDate: '2024-01-01',
endDate: '2024-12-31'
});

// Auto-completion for all properties
console.log(protocol.name);
console.log(protocol.totalValueLocked);
console.log(protocol.chains);

Publishing to npm

# Build the package
npm run build

# Test locally
npm link

# Publish to npm
npm login
npm publish --access public

# Or to a private registry
npm publish --registry https://registry.your-org.com

Python

Generation

# Using the provided script
./scripts/generate-python-sdk.sh ./sdk-output

# Or using openapi-generator directly
openapi-generator-cli generate \
-i openapi.yaml \
-g python \
-o ./python-sdk \
--additional-properties=packageName=tvl_sdk,library=asyncio

Configuration Options

# Environment variables
export PACKAGE_NAME="tvl-sdk"
export PACKAGE_VERSION="1.0.0"
export OPENAPI_SPEC="./openapi.yaml"

./scripts/generate-python-sdk.sh

Installation & Usage

Install:

cd python-sdk
pip install -r requirements.txt
python setup.py install

# Or for development
pip install -e .

Basic Usage:

from tvl_sdk import TvlSdk

# Initialize
sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
timeout=30,
retry_attempts=3
)

# Get protocols
protocols = sdk.protocols.get_protocols()
print(protocols)

# Get specific protocol
protocol = sdk.protocols.get_protocol_by_id(id="uniswap")
print(f"Protocol: {protocol.name}")
print(f"TVL: ${protocol.total_value_locked:,.2f}")

Async/Await Support

import asyncio
from tvl_sdk import AsyncTvlSdk

async def main():
# Use async context manager
async with AsyncTvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key"
) as sdk:
# Fetch multiple endpoints concurrently
protocols_task = sdk.protocols.get_protocols()
chains_task = sdk.chains.get_chains()

protocols, chains = await asyncio.gather(
protocols_task,
chains_task
)

print(f"Protocols: {len(protocols)}")
print(f"Chains: {len(chains)}")

# Run async code
asyncio.run(main())

Type Hints with Pydantic

from tvl_sdk import TvlSdk, Protocol, ProtocolTvlHistory
from typing import List
from datetime import date

sdk = TvlSdk(api_key="your-api-key")

# Type-safe responses
protocol: Protocol = sdk.protocols.get_protocol_by_id(id="uniswap")

# Type-safe requests
history: List[ProtocolTvlHistory] = sdk.protocols.get_protocol_tvl_history(
id="uniswap",
start_date=date(2024, 1, 1),
end_date=date(2024, 12, 31)
)

# Pydantic models provide validation
print(protocol.name) # IDE auto-completion
print(protocol.total_value_locked)

Error Handling

from tvl_sdk import TvlSdk, ApiException

sdk = TvlSdk(api_key="your-api-key")

try:
protocol = sdk.protocols.get_protocol_by_id(id="invalid")
except ApiException as e:
print(f"API Error: {e.status} - {e.reason}")
print(f"Body: {e.body}")

if e.status == 404:
print("Protocol not found")
elif e.status == 429:
print("Rate limit exceeded")

Custom Configuration

from tvl_sdk import TvlSdk

# Custom error handler
def handle_error(error):
print(f"Error occurred: {error}")
# Send to monitoring service
# send_to_sentry(error)

sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
timeout=60,
retry_attempts=5,
retry_delay=2.0,
on_error=handle_error
)

# Update configuration at runtime
sdk.update_config(
api_key="new-api-key",
timeout=90
)

Publishing to PyPI

# Build the package
python setup.py sdist bdist_wheel

# Test with TestPyPI
twine upload --repository testpypi dist/*

# Install from TestPyPI
pip install --index-url https://test.pypi.org/simple/ tvl-sdk

# Publish to PyPI
twine upload dist/*

Java

Generation

openapi-generator-cli generate \
-i openapi.yaml \
-g java \
-o ./java-sdk \
--additional-properties=\
groupId=com.tvl,\
artifactId=tvl-sdk,\
invokerPackage=com.tvl.client,\
apiPackage=com.tvl.api,\
modelPackage=com.tvl.model,\
library=okhttp-gson

Maven Setup

pom.xml:

<dependency>
<groupId>com.tvl</groupId>
<artifactId>tvl-sdk</artifactId>
<version>1.0.0</version>
</dependency>

Gradle Setup

build.gradle:

dependencies {
implementation 'com.tvl:tvl-sdk:1.0.0'
}

Usage Examples

import com.tvl.client.ApiClient;
import com.tvl.client.Configuration;
import com.tvl.api.ProtocolsApi;
import com.tvl.model.Protocol;

public class TvlExample {
public static void main(String[] args) {
// Configure API client
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://api.tvl.com/v1");
client.setApiKey("your-api-key");

// Create API instance
ProtocolsApi api = new ProtocolsApi(client);

try {
// Get all protocols
List<Protocol> protocols = api.getProtocols();

// Get specific protocol
Protocol protocol = api.getProtocolById("uniswap");
System.out.println("Protocol: " + protocol.getName());
System.out.println("TVL: $" + protocol.getTotalValueLocked());

} catch (ApiException e) {
System.err.println("API Error: " + e.getCode());
System.err.println("Response: " + e.getResponseBody());
}
}
}

Go

Generation

openapi-generator-cli generate \
-i openapi.yaml \
-g go \
-o ./go-sdk \
--additional-properties=\
packageName=tvlsdk,\
packageVersion=1.0.0

Module Setup

cd go-sdk
go mod init github.com/yourusername/tvl-sdk
go mod tidy

Usage Examples

package main

import (
"context"
"fmt"
"github.com/yourusername/tvl-sdk"
)

func main() {
// Configure client
cfg := tvlsdk.NewConfiguration()
cfg.Servers = tvlsdk.ServerConfigurations{
{
URL: "https://api.tvl.com/v1",
},
}
cfg.AddDefaultHeader("X-API-Key", "your-api-key")

// Create client
client := tvlsdk.NewAPIClient(cfg)
ctx := context.Background()

// Get protocols
protocols, resp, err := client.ProtocolsApi.GetProtocols(ctx).Execute()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}

fmt.Printf("Status: %d\n", resp.StatusCode)
fmt.Printf("Protocols: %d\n", len(protocols))

// Get specific protocol
protocol, _, err := client.ProtocolsApi.GetProtocolById(ctx, "uniswap").Execute()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}

fmt.Printf("Protocol: %s\n", protocol.Name)
fmt.Printf("TVL: $%.2f\n", protocol.TotalValueLocked)
}

Customization

Custom Templates

Create Custom Template Directory

mkdir -p ./custom-templates/typescript-axios

Override API Template

{{! custom-templates/typescript-axios/api.mustache }}
/**
* {{classname}}
* Custom template with additional features
*/

import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { Configuration } from '../configuration';

{{#operations}}
export class {{classname}} {
// Your custom implementation

{{#operation}}
/**
* {{summary}}
* {{notes}}
*/
public async {{nickname}}({{#allParams}}{{paramName}}: {{dataType}}{{^required}}?{{/required}}{{^-last}}, {{/-last}}{{/allParams}}): Promise<{{returnType}}> {
// Custom implementation
}
{{/operation}}
}
{{/operations}}

Use Custom Templates

openapi-generator-cli generate \
-i openapi.yaml \
-g typescript-axios \
-o ./sdk \
-t ./custom-templates/typescript-axios

Configuration Files

Create Config File

# openapi-generator-config.yaml
generatorName: typescript-axios
inputSpec: openapi.yaml
outputDir: ./generated-sdk

additionalProperties:
npmName: "@tvl/sdk"
npmVersion: "1.0.0"
supportsES6: true
withInterfaces: true

globalProperties:
models: true
apis: true
supportingFiles: true

# Custom template location
templateDir: ./custom-templates

Generate with Config

openapi-generator-cli generate -c openapi-generator-config.yaml

Adding Middleware/Interceptors

TypeScript Example

// middleware/logger.ts
export function createLoggerMiddleware() {
return {
onRequest: (config: any) => {
console.log(`[${new Date().toISOString()}] ${config.method?.toUpperCase()} ${config.url}`);
return config;
},
onResponse: (response: any) => {
console.log(`[${new Date().toISOString()}] ${response.status} ${response.config.url}`);
return response;
}
};
}

// usage
import { TvlSdk } from '@tvl/sdk';
import { createLoggerMiddleware } from './middleware/logger';

const logger = createLoggerMiddleware();

const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key',
...logger
});

Python Example

# middleware/logger.py
import logging
from datetime import datetime

logger = logging.getLogger(__name__)

def log_request(request):
logger.info(f"[{datetime.now().isoformat()}] {request.method} {request.url}")
return request

def log_response(response):
logger.info(f"[{datetime.now().isoformat()}] {response.status_code} {response.url}")
return response

# usage
from tvl_sdk import TvlSdk
from middleware.logger import log_request, log_response

sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
on_request=log_request,
on_response=log_response
)

Custom Error Handling

TypeScript

class TvlApiError extends Error {
constructor(
message: string,
public status: number,
public code: string,
public data: any
) {
super(message);
this.name = 'TvlApiError';
}
}

const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key',
onError: (error) => {
throw new TvlApiError(
error.message,
error.status,
error.code,
error.data
);
}
});

Python

class TvlApiError(Exception):
def __init__(self, message, status, code, data):
super().__init__(message)
self.status = status
self.code = code
self.data = data

def handle_error(error):
raise TvlApiError(
str(error),
getattr(error, 'status', None),
getattr(error, 'code', None),
getattr(error, 'body', None)
)

sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
on_error=handle_error
)

Testing Generated SDKs

Unit Testing

TypeScript (Jest)

// __tests__/sdk.test.ts
import { TvlSdk } from '@tvl/sdk';
import axios from 'axios';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

describe('TvlSdk', () => {
let sdk: TvlSdk;

beforeEach(() => {
sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'test-api-key'
});
});

test('should fetch protocols', async () => {
const mockProtocols = [
{ id: 'uniswap', name: 'Uniswap', tvl: 1000000 }
];

mockedAxios.get.mockResolvedValue({
data: mockProtocols,
status: 200
});

const protocols = await sdk.protocols.getProtocols();
expect(protocols.data).toEqual(mockProtocols);
});

test('should handle errors', async () => {
mockedAxios.get.mockRejectedValue({
response: { status: 404, data: { message: 'Not found' } }
});

await expect(sdk.protocols.getProtocolById({ id: 'invalid' }))
.rejects.toThrow();
});
});

Python (pytest)

# tests/test_sdk.py
import pytest
from unittest.mock import Mock, patch
from tvl_sdk import TvlSdk, ApiException

@pytest.fixture
def sdk():
return TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="test-api-key"
)

def test_get_protocols(sdk):
with patch.object(sdk.protocols, 'get_protocols') as mock_get:
mock_get.return_value = [
{"id": "uniswap", "name": "Uniswap", "tvl": 1000000}
]

protocols = sdk.protocols.get_protocols()
assert len(protocols) == 1
assert protocols[0]["name"] == "Uniswap"

def test_error_handling(sdk):
with patch.object(sdk.protocols, 'get_protocol_by_id') as mock_get:
mock_get.side_effect = ApiException(status=404, reason="Not found")

with pytest.raises(ApiException) as exc_info:
sdk.protocols.get_protocol_by_id(id="invalid")

assert exc_info.value.status == 404

Integration Testing

Mock Server Setup

// mock-server.js
const express = require('express');
const app = express();

app.get('/v1/protocols', (req, res) => {
res.json([
{ id: 'uniswap', name: 'Uniswap', tvl: 1000000 },
{ id: 'aave', name: 'Aave', tvl: 2000000 }
]);
});

app.get('/v1/protocols/:id', (req, res) => {
const { id } = req.params;
if (id === 'uniswap') {
res.json({ id: 'uniswap', name: 'Uniswap', tvl: 1000000 });
} else {
res.status(404).json({ error: 'Not found' });
}
});

app.listen(3000, () => {
console.log('Mock server running on port 3000');
});

Integration Test

// integration/sdk.integration.test.ts
import { TvlSdk } from '@tvl/sdk';

describe('SDK Integration Tests', () => {
let sdk: TvlSdk;

beforeAll(() => {
// Point to mock server
sdk = new TvlSdk({
baseURL: 'http://localhost:3000/v1',
apiKey: 'test-key'
});
});

test('should fetch protocols from mock server', async () => {
const protocols = await sdk.protocols.getProtocols();
expect(protocols.data).toHaveLength(2);
expect(protocols.data[0].name).toBe('Uniswap');
});

test('should handle 404 errors', async () => {
await expect(
sdk.protocols.getProtocolById({ id: 'nonexistent' })
).rejects.toMatchObject({
status: 404
});
});
});

CI/CD Integration

Auto-Generate on OpenAPI Changes

GitHub Actions

# .github/workflows/generate-sdks.yml
name: Generate SDKs

on:
push:
paths:
- 'openapi.yaml'
- 'openapi/**'
branches:
- main

jobs:
generate:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install OpenAPI Generator
run: npm install -g @openapitools/openapi-generator-cli

- name: Generate TypeScript SDK
run: ./scripts/generate-typescript-sdk.sh ./sdks/typescript

- name: Generate Python SDK
run: ./scripts/generate-python-sdk.sh ./sdks/python

- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
commit-message: 'chore: regenerate SDKs'
title: 'Auto-generated SDK updates'
body: 'SDKs regenerated from OpenAPI spec changes'
branch: sdk-updates

Version Management

Semantic Versioning Script

#!/bin/bash
# scripts/version-sdk.sh

VERSION_FILE="./VERSION"
CURRENT_VERSION=$(cat $VERSION_FILE)

# Parse version
IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT_VERSION"
MAJOR="${VERSION_PARTS[0]}"
MINOR="${VERSION_PARTS[1]}"
PATCH="${VERSION_PARTS[2]}"

# Increment based on argument
case $1 in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
*)
echo "Usage: $0 {major|minor|patch}"
exit 1
;;
esac

NEW_VERSION="$MAJOR.$MINOR.$PATCH"
echo $NEW_VERSION > $VERSION_FILE

echo "Version updated: $CURRENT_VERSION -> $NEW_VERSION"

# Update package files
export PACKAGE_VERSION=$NEW_VERSION
./scripts/generate-sdk.sh --all

Publishing Workflow

TypeScript to npm

# .github/workflows/publish-typescript-sdk.yml
name: Publish TypeScript SDK

on:
release:
types: [created]

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
working-directory: ./sdks/typescript
run: npm install

- name: Build
working-directory: ./sdks/typescript
run: npm run build

- name: Publish to npm
working-directory: ./sdks/typescript
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Python to PyPI

# .github/workflows/publish-python-sdk.yml
name: Publish Python SDK

on:
release:
types: [created]

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: |
pip install build twine

- name: Build package
working-directory: ./sdks/python
run: python -m build

- name: Publish to PyPI
working-directory: ./sdks/python
run: twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}

SDK Usage Examples

Complete TypeScript Example

import { TvlSdk } from '@tvl/sdk';

// Initialize SDK
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: process.env.TVL_API_KEY,
timeout: 30000,
retryAttempts: 3,
retryDelay: 1000
});

// Example 1: Get all protocols
async function getAllProtocols() {
try {
const response = await sdk.protocols.getProtocols();
console.log(`Found ${response.data.length} protocols`);

response.data.forEach(protocol => {
console.log(`${protocol.name}: $${protocol.totalValueLocked.toLocaleString()}`);
});

return response.data;
} catch (error) {
console.error('Failed to fetch protocols:', error.message);
throw error;
}
}

// Example 2: Get protocol with pagination
async function getProtocolsWithPagination() {
let page = 1;
let hasMore = true;
const allProtocols = [];

while (hasMore) {
const response = await sdk.protocols.getProtocols({
page,
limit: 100
});

allProtocols.push(...response.data);

hasMore = response.data.length === 100;
page++;
}

return allProtocols;
}

// Example 3: Error handling
async function getProtocolSafely(id: string) {
try {
const protocol = await sdk.protocols.getProtocolById({ id });
return protocol.data;
} catch (error) {
if (error.status === 404) {
console.log(`Protocol ${id} not found`);
return null;
} else if (error.status === 429) {
console.log('Rate limit exceeded, waiting...');
await new Promise(resolve => setTimeout(resolve, 5000));
return getProtocolSafely(id); // Retry
} else {
throw error;
}
}
}

// Example 4: Parallel requests
async function getMultipleProtocols(ids: string[]) {
const promises = ids.map(id =>
sdk.protocols.getProtocolById({ id })
.then(res => res.data)
.catch(err => null)
);

return Promise.all(promises);
}

// Example 5: Stream processing
async function* streamProtocols() {
let page = 1;
let hasMore = true;

while (hasMore) {
const response = await sdk.protocols.getProtocols({
page,
limit: 50
});

for (const protocol of response.data) {
yield protocol;
}

hasMore = response.data.length === 50;
page++;
}
}

// Usage
(async () => {
// Get all protocols
await getAllProtocols();

// Get with pagination
const allProtocols = await getProtocolsWithPagination();
console.log(`Total protocols: ${allProtocols.length}`);

// Get multiple protocols
const protocols = await getMultipleProtocols(['uniswap', 'aave', 'compound']);
console.log('Fetched protocols:', protocols.filter(p => p !== null).length);

// Stream processing
for await (const protocol of streamProtocols()) {
console.log(`Processing: ${protocol.name}`);
// Process each protocol
}
})();

Complete Python Example

import asyncio
from typing import List, AsyncGenerator
from tvl_sdk import TvlSdk, AsyncTvlSdk, Protocol, ApiException

# Initialize SDK
sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
timeout=30,
retry_attempts=3,
retry_delay=1.0
)

# Example 1: Get all protocols
def get_all_protocols() -> List[Protocol]:
try:
protocols = sdk.protocols.get_protocols()
print(f"Found {len(protocols)} protocols")

for protocol in protocols:
print(f"{protocol.name}: ${protocol.total_value_locked:,.2f}")

return protocols
except ApiException as e:
print(f"Failed to fetch protocols: {e.reason}")
raise

# Example 2: Get protocols with pagination
def get_protocols_with_pagination() -> List[Protocol]:
page = 1
all_protocols = []

while True:
protocols = sdk.protocols.get_protocols(
page=page,
limit=100
)

all_protocols.extend(protocols)

if len(protocols) < 100:
break

page += 1

return all_protocols

# Example 3: Error handling
def get_protocol_safely(protocol_id: str):
try:
protocol = sdk.protocols.get_protocol_by_id(id=protocol_id)
return protocol
except ApiException as e:
if e.status == 404:
print(f"Protocol {protocol_id} not found")
return None
elif e.status == 429:
print("Rate limit exceeded, waiting...")
import time
time.sleep(5)
return get_protocol_safely(protocol_id) # Retry
else:
raise

# Example 4: Async parallel requests
async def get_multiple_protocols_async(ids: List[str]):
async with AsyncTvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key"
) as sdk:
tasks = []

for protocol_id in ids:
task = sdk.protocols.get_protocol_by_id(id=protocol_id)
tasks.append(task)

results = await asyncio.gather(*tasks, return_exceptions=True)

protocols = []
for result in results:
if isinstance(result, Exception):
print(f"Error: {result}")
else:
protocols.append(result)

return protocols

# Example 5: Async stream processing
async def stream_protocols_async() -> AsyncGenerator[Protocol, None]:
async with AsyncTvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key"
) as sdk:
page = 1

while True:
protocols = await sdk.protocols.get_protocols(
page=page,
limit=50
)

for protocol in protocols:
yield protocol

if len(protocols) < 50:
break

page += 1

# Example 6: Context manager for cleanup
class TvlAnalyzer:
def __init__(self, api_key: str):
self.sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key=api_key
)

def analyze_protocol(self, protocol_id: str):
protocol = self.sdk.protocols.get_protocol_by_id(id=protocol_id)
history = self.sdk.protocols.get_protocol_tvl_history(
id=protocol_id,
start_date="2024-01-01",
end_date="2024-12-31"
)

return {
"name": protocol.name,
"current_tvl": protocol.total_value_locked,
"historical_data": history,
"growth": self._calculate_growth(history)
}

def _calculate_growth(self, history):
if len(history) < 2:
return 0

start_tvl = history[0].tvl
end_tvl = history[-1].tvl

return ((end_tvl - start_tvl) / start_tvl) * 100

# Usage
if __name__ == "__main__":
# Sync examples
protocols = get_all_protocols()
all_protocols = get_protocols_with_pagination()
print(f"Total protocols: {len(all_protocols)}")

# Safe fetch
protocol = get_protocol_safely("uniswap")
if protocol:
print(f"Found: {protocol.name}")

# Async examples
async def main():
# Parallel fetch
protocols = await get_multiple_protocols_async([
"uniswap", "aave", "compound"
])
print(f"Fetched {len(protocols)} protocols")

# Stream processing
async for protocol in stream_protocols_async():
print(f"Processing: {protocol.name}")
# Process each protocol

asyncio.run(main())

# Analyzer
analyzer = TvlAnalyzer(api_key="your-api-key")
analysis = analyzer.analyze_protocol("uniswap")
print(f"Growth: {analysis['growth']:.2f}%")

Troubleshooting

Common Issues

1. OpenAPI Generator Not Found

Error:

openapi-generator-cli: command not found

Solution:

# Install via npm
npm install -g @openapitools/openapi-generator-cli

# Or via Homebrew
brew install openapi-generator

# Verify installation
openapi-generator-cli version

2. Invalid OpenAPI Specification

Error:

Validation error: ...

Solution:

# Validate spec
openapi-generator-cli validate -i openapi.yaml

# Use --skip-validate-spec flag
./scripts/generate-sdk.sh typescript --skip-validate

3. TypeScript Compilation Errors

Error:

TS2304: Cannot find name 'Promise'

Solution:

// Update tsconfig.json
{
"compilerOptions": {
"lib": ["ES2018", "DOM"],
"target": "ES2018"
}
}

4. Python Import Errors

Error:

ModuleNotFoundError: No module named 'tvl_sdk'

Solution:

# Install in development mode
pip install -e .

# Or install normally
python setup.py install

# Verify installation
python -c "import tvl_sdk; print(tvl_sdk.__version__)"

5. Authentication Failures

Error:

401 Unauthorized

Solution:

// Check API key format
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: process.env.TVL_API_KEY // Ensure this is set
});

// Verify API key is being sent
sdk.updateConfig({
onRequest: (config) => {
console.log('Headers:', config.headers);
return config;
}
});

6. Rate Limiting

Error:

429 Too Many Requests

Solution:

// Increase retry delay
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key',
retryAttempts: 5,
retryDelay: 2000, // 2 seconds
onError: (error) => {
if (error.status === 429) {
const retryAfter = error.headers?.['retry-after'];
console.log(`Rate limited. Retry after: ${retryAfter}s`);
}
}
});

Debug Mode

TypeScript

// Enable debug logging
const sdk = new TvlSdk({
baseURL: 'https://api.tvl.com/v1',
apiKey: 'your-api-key',
onRequest: (config) => {
console.log('REQUEST:', {
method: config.method,
url: config.url,
headers: config.headers,
data: config.data
});
return config;
},
onResponse: (response) => {
console.log('RESPONSE:', {
status: response.status,
headers: response.headers,
data: response.data
});
return response;
},
onError: (error) => {
console.error('ERROR:', {
message: error.message,
status: error.status,
data: error.data
});
}
});

Python

import logging

# Enable debug logging
logging.basicConfig(level=logging.DEBUG)

sdk = TvlSdk(
base_url="https://api.tvl.com/v1",
api_key="your-api-key",
on_error=lambda e: logging.error(f"API Error: {e}")
)

Getting Help

If you encounter issues not covered here:

  1. Check the documentation: https://docs.tvl.com
  2. Search existing issues: https://github.com/tvl/sdks/issues
  3. Join our Discord: https://discord.gg/tvl
  4. Contact support: support@tvl.com

Resources

External Resources

Community


Changelog

Version 1.0.0 (2024-01-15)

  • Initial release
  • Support for TypeScript, Python, Java, Go, Ruby, PHP
  • Retry logic and error handling
  • Async support for TypeScript and Python
  • Type safety and validation
  • Comprehensive documentation

Need help? Contact us at support@tvl.com or open an issue on GitHub.