Skip to main content

API Usage

Variant-Linker can be used as both a command-line tool and a JavaScript library. This guide explains the key differences between API and CLI usage, helping you choose the right approach for your project.

Overview: API vs CLI

When to Use the API

  • Node.js applications: Integrating variant annotation into existing JavaScript/Node.js projects
  • Custom workflows: Building complex pipelines with custom logic and data processing
  • Real-time processing: Interactive applications requiring immediate responses
  • Memory efficiency: Processing results in memory without file I/O overhead
  • Custom error handling: Applications requiring specific error handling strategies

When to Use the CLI

  • Standalone analysis: One-off variant annotation tasks
  • Batch processing: Large-scale file-based variant processing
  • Shell scripting: Integration into bash/shell-based workflows
  • Standard formats: Working primarily with VCF, CSV, or JSON files
  • Simple automation: Basic pipeline automation without complex logic

Basic API Usage

Installation as a Library

npm install variant-linker

Simple Variant Analysis

const { analyzeVariant } = require('variant-linker');

async function analyzeVariants() {
try {
// Single variant analysis
const result = await analyzeVariant({
variant: 'rs6025',
output: 'JSON'
});

console.log(result);
} catch (error) {
console.error('Analysis failed:', error.message);
}
}

analyzeVariants();

Batch Processing

const { analyzeVariant } = require('variant-linker');

async function processBatch() {
const variants = ['rs6025', 'ENST00000366667:c.803C>T', 'rs1799963'];

const result = await analyzeVariant({
variants: variants,
recoderOptions: { vcf_string: '1' },
vepOptions: { CADD: '1', SIFT: '1', PolyPhen: '1' },
output: 'JSON'
});

return result;
}

Key Differences: API vs CLI

1. Configuration

CLI Configuration

# File-based configuration
variant-linker --config config.json --scoring_config_path scoring/nephro_variant_score/

# Command-line parameters
variant-linker --variant "rs6025" --vep_params "CADD=1,SIFT=1" --output JSON

API Configuration

// Object-based configuration
const { analyzeVariant, scoring } = require('variant-linker');

// Load scoring configuration from files (Node.js only)
const scoringConfig = await scoring.readScoringConfigFromFiles('scoring/nephro_variant_score/');

// Or parse configuration objects directly
const scoringConfig = scoring.parseScoringConfig(
{ variables: { /* variable definitions */ } },
{ formulas: { /* scoring formulas */ } }
);

const result = await analyzeVariant({
variant: 'rs6025',
vepOptions: { CADD: '1', SIFT: '1' },
scoringConfig: scoringConfig,
output: 'JSON'
});

Key Differences:

  • CLI: Uses file paths and comma-separated parameter strings
  • API: Uses JavaScript objects and structured data
  • Scoring: CLI loads from directory path; API accepts parsed objects or loads via helper functions

2. Error Handling

CLI Error Handling

# CLI exits with status codes
variant-linker --variant "invalid" --output JSON
echo $? # Returns non-zero exit code on failure

# JSON error output to stderr
{
"status": "error",
"message": "Invalid variant format"
}

API Error Handling

// API throws exceptions
try {
const result = await analyzeVariant({
variant: 'invalid',
output: 'JSON'
});
} catch (error) {
// Handle different error types
if (error.name === 'ValidationError') {
console.error('Input validation failed:', error.message);
} else if (error.name === 'APIError') {
console.error('External API error:', error.message, error.statusCode);
} else {
console.error('Unexpected error:', error);
}
}

Key Differences:

  • CLI: Uses exit codes (0 = success, non-zero = error) and JSON error output
  • API: Throws typed exceptions with detailed error information
  • Recovery: API allows for programmatic error recovery and retry logic

3. Input/Output Handling

CLI Input/Output

# File-based I/O
variant-linker --vcf-input sample.vcf --output VCF --save annotated.vcf

# String/console I/O
variant-linker --variant "rs6025" --output JSON > result.json

API Input/Output

// Data structure I/O
const fs = require('fs');
const { analyzeVariant, convertVcfToEnsemblFormat } = require('variant-linker');

// Process VCF data in memory
const vcfContent = fs.readFileSync('sample.vcf', 'utf8');
const variants = convertVcfToEnsemblFormat(vcfContent);

const results = await analyzeVariant({
variants: variants,
output: 'JSON'
});

// Results are JavaScript objects/arrays
results.forEach(variant => {
console.log(`Variant: ${variant.input}`);
console.log(`Consequences: ${variant.most_severe_consequence}`);
});

Key Differences:

  • CLI: File streams, command-line strings, and saved output files
  • API: JavaScript arrays, objects, and in-memory data structures
  • Flexibility: API provides direct access to parsed data structures

4. Dependencies and Environment

CLI Environment

# Global installation
npm install -g variant-linker
variant-linker --version

# Local execution
npx variant-linker --variant "rs6025"

# Shell integration
for variant in rs6025 rs1799963; do
variant-linker --variant "$variant" --output JSON
done

API Environment

// Node.js environment required
const { analyzeVariant, cache } = require('variant-linker');

// Browser environment (with webpack bundle)
// Note: File system operations not available in browser
import VariantLinker from './dist/variant-linker.bundle.js';

// Environment detection
if (typeof window !== 'undefined') {
// Browser environment - limited functionality
console.log('Running in browser');
} else {
// Node.js environment - full functionality
console.log('Running in Node.js');
}

Key Differences:

  • CLI: Requires Node.js runtime, works in any shell environment
  • API: Node.js for full functionality, limited browser support via webpack bundle
  • File operations: CLI has full file system access; browser API is limited

5. State Management and Caching

CLI State Management

# Each CLI invocation is independent
variant-linker --variant "rs6025" --output JSON # Fresh cache
variant-linker --variant "rs6025" --output JSON # Cache may be used

# No persistent state between CLI calls

API State Management

const { analyzeVariant, cache } = require('variant-linker');

// Persistent cache across API calls
await analyzeVariant({ variant: 'rs6025', output: 'JSON' }); // API call made
await analyzeVariant({ variant: 'rs6025', output: 'JSON' }); // Cache hit

// Manual cache management
cache.clearCache(); // Clear all cached data

// Cache is shared across all API usage in the same Node.js process

Key Differences:

  • CLI: Independent cache per process, automatically cleaned up
  • API: Persistent cache within Node.js process, manual management available
  • Memory: API cache persists until process ends or manually cleared

Advanced API Usage

Custom Error Handling

const { analyzeVariant, apiHelper } = require('variant-linker');

async function robustAnalysis(variants) {
const results = [];
const errors = [];

for (const variant of variants) {
try {
const result = await analyzeVariant({
variant: variant,
output: 'JSON'
});
results.push(result);
} catch (error) {
errors.push({ variant, error: error.message });

// Implement custom retry logic
if (error.statusCode === 429) { // Rate limited
await new Promise(resolve => setTimeout(resolve, 5000));
// Retry logic here
}
}
}

return { results, errors };
}

Custom Processing Pipeline

const { 
variantRecoderPost,
vepRegionsAnnotation,
processVariantLinking,
scoring
} = require('variant-linker');

async function customPipeline(variants) {
// Step 1: Variant recoding
const recodedVariants = await variantRecoderPost(variants, {
vcf_string: '1'
});

// Step 2: VEP annotation
const annotations = await vepRegionsAnnotation(recodedVariants, {
CADD: '1',
SIFT: '1',
PolyPhen: '1'
});

// Step 3: Custom processing
const processed = processVariantLinking(recodedVariants, annotations);

// Step 4: Apply custom scoring
const scoringConfig = scoring.parseScoringConfig(
myVariableConfig,
myFormulaConfig
);

const scored = scoring.applyScoring(processed, scoringConfig);

return scored;
}

Memory-Efficient Batch Processing

async function processLargeBatch(variants, chunkSize = 200) {
const results = [];

for (let i = 0; i < variants.length; i += chunkSize) {
const chunk = variants.slice(i, i + chunkSize);

const chunkResults = await analyzeVariant({
variants: chunk,
output: 'JSON'
});

results.push(...chunkResults);

// Optional: Clear cache periodically to manage memory
if (i % 1000 === 0) {
cache.clearCache();
}
}

return results;
}

Best Practices

API Best Practices

  1. Error Handling: Always wrap API calls in try-catch blocks
  2. Batching: Use batch processing for multiple variants to reduce API calls
  3. Caching: Monitor cache usage and clear when processing large datasets
  4. Configuration: Validate configuration objects before passing to API functions
  5. Memory Management: Consider clearing cache for long-running processes

When to Choose API vs CLI

  • Choose API for: Integration into applications, custom error handling, memory efficiency, real-time processing
  • Choose CLI for: File-based workflows, shell scripting, standalone analysis, standard output formats

Migration from CLI to API

CLI Command Translation

# CLI command
variant-linker --variants-file variants.txt --scoring_config_path scoring/nephro/ --output CSV --save results.csv
// Equivalent API usage
const fs = require('fs');
const { analyzeVariant, scoring } = require('variant-linker');

async function migrate() {
// Read variants file
const variantsFile = fs.readFileSync('variants.txt', 'utf8');
const variants = variantsFile.split('\n').filter(line => line.trim());

// Load scoring configuration
const scoringConfig = await scoring.readScoringConfigFromFiles('scoring/nephro/');

// Analyze variants
const results = await analyzeVariant({
variants: variants,
scoringConfig: scoringConfig,
output: 'CSV'
});

// Save results
fs.writeFileSync('results.csv', results);
}

Next Steps