JavaScript Examples
This page provides comprehensive JavaScript examples for both Node.js and browser environments. All examples demonstrate best practices for authentication, error handling, and context retrieval.Node.js Setup
Copy
npm install node-fetch dotenv
Copy
// config.js
export const CONFIG = {
BASE_URL: "https://www.goharvest.ai/api/v1/developer",
API_KEY: process.env.HARVEST_API_KEY,
HEADERS: {
"API-Key": process.env.HARVEST_API_KEY,
"Content-Type": "application/json",
},
};
Complete Context Retrieval Client
Copy
// HarvestContextClient.js
import { CONFIG } from './config.js';
export class HarvestContextClient {
constructor(apiKey = CONFIG.API_KEY) {
this.apiKey = apiKey;
this.baseUrl = CONFIG.BASE_URL;
this.headers = {
'API-Key': apiKey,
'Content-Type': 'application/json'
};
}
async listIndexes() {
/**
* List all available indexed services
*/
const url = `${this.baseUrl}/list-indexes`;
try {
const response = await fetch(url, {
headers: this.headers,
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (result.ok) {
console.log(`✅ Found ${result.data.indexes.length} indexed services`);
return result.data.indexes;
} else {
console.error(`❌ Error: ${result.error}`);
return [];
}
} catch (error) {
console.error('❌ Error listing indexes:', error);
return [];
}
}
async getContext(indexId, query) {
/**
* Retrieve context from a specific indexed service
*/
const url = `${this.baseUrl}/get-context`;
const payload = {
query: query,
index_id: indexId
};
try {
const response = await fetch(url, {
method: 'POST',
headers: this.headers,
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
if (result.ok) {
const context = result.data.context;
console.log(`✅ Retrieved context (${context.length} characters)`);
return context;
} else {
console.error(`❌ Error: ${result.error}`);
return null;
}
} catch (error) {
console.error('❌ Error getting context:', error);
return null;
}
}
async searchByServiceName(serviceName, query) {
/**
* Find a service by name and retrieve context
*/
const indexes = await this.listIndexes();
// Find matching service (case-insensitive)
const matchingService = indexes.find(idx =>
idx.name.toLowerCase().includes(serviceName.toLowerCase())
);
if (!matchingService) {
console.error(`❌ Service '${serviceName}' not found`);
console.log(`Available services: ${indexes.map(idx => idx.name).join(', ')}`);
return null;
}
console.log(`🔍 Found service: ${matchingService.name} (${matchingService.type})`);
return this.getContext(matchingService.index_id, query);
}
async queryMultipleServices(query, serviceTypes = null) {
/**
* Query multiple services with the same question
* Optionally filter by service types (e.g., ['SDK', 'API'])
*/
const indexes = await this.listIndexes();
// Filter by type if specified
const filteredIndexes = serviceTypes
? indexes.filter(idx => serviceTypes.includes(idx.type))
: indexes;
console.log(`🔍 Querying ${filteredIndexes.length} services for: "${query}"`);
const results = [];
for (const index of filteredIndexes) {
console.log(`\n📖 Querying ${index.name} (${index.type})...`);
const context = await this.getContext(index.index_id, query);
results.push({
service: index.name,
type: index.type,
index_id: index.index_id,
context: context,
success: context !== null
});
}
return results;
}
}
// Usage examples
async function main() {
const client = new HarvestContextClient();
// Example 1: List all available services
console.log("Example 1: Listing all services\n");
const indexes = await client.listIndexes();
indexes.forEach(idx => {
console.log(` - ${idx.name} (${idx.type}): ${idx.index_id}`);
});
// Example 2: Get context from first available service
if (indexes.length > 0) {
console.log("\nExample 2: Getting context\n");
const firstIndex = indexes[0];
const context = await client.getContext(
firstIndex.index_id,
"how to make authenticated POST request"
);
if (context) {
const preview = context.length > 500 ? context.substring(0, 500) + "..." : context;
console.log(preview);
}
}
// Example 3: Search by service name
console.log("\nExample 3: Search by service name\n");
const context = await client.searchByServiceName(
"Python",
"how to handle exceptions"
);
// Example 4: Query all SDK services
console.log("\nExample 4: Query multiple services by type\n");
const results = await client.queryMultipleServices(
"authentication example",
['SDK', 'API']
);
console.log("\n📊 Results summary:");
results.forEach(result => {
const status = result.success ? "✅" : "❌";
const length = result.context ? result.context.length : 0;
console.log(`${status} ${result.service}: ${length} characters`);
});
}
// Run if this is the main module
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch(console.error);
}
Browser-Based Example
For client-side applications:Copy
<!DOCTYPE html>
<html>
<head>
<title>Harvest Context Demo</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
select, input, button { padding: 10px; margin: 5px 0; width: 100%; }
#result { background: #f5f5f5; padding: 20px; margin-top: 20px; white-space: pre-wrap; }
.loading { color: #666; font-style: italic; }
</style>
</head>
<body>
<h1>Harvest Context API Demo</h1>
<div>
<label>Service:</label>
<select id="serviceSelect">
<option>Loading services...</option>
</select>
</div>
<div>
<label>Query:</label>
<input type="text" id="queryInput" placeholder="e.g., how to authenticate">
</div>
<button onclick="getContext()">Get Context</button>
<div id="result"></div>
<script>
const API_KEY = 'your-api-key-here'; // In production, use secure method
const BASE_URL = 'https://www.goharvest.ai/api/v1/developer';
let indexes = [];
// Load services on page load
window.onload = async () => {
try {
const response = await fetch(`${BASE_URL}/list-indexes`, {
headers: { 'API-Key': API_KEY }
});
const result = await response.json();
if (result.ok) {
indexes = result.data.indexes;
const select = document.getElementById('serviceSelect');
select.innerHTML = indexes.map((idx, i) =>
`<option value="${i}">${idx.name} (${idx.type})</option>`
).join('');
}
} catch (error) {
document.getElementById('serviceSelect').innerHTML =
'<option>Error loading services</option>';
console.error(error);
}
};
async function getContext() {
const select = document.getElementById('serviceSelect');
const queryInput = document.getElementById('queryInput');
const resultDiv = document.getElementById('result');
const selectedIndex = indexes[select.value];
const query = queryInput.value;
if (!query) {
alert('Please enter a query');
return;
}
resultDiv.innerHTML = '<div class="loading">Loading context...</div>';
try {
const response = await fetch(`${BASE_URL}/get-context`, {
method: 'POST',
headers: {
'API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: query,
index_id: selectedIndex.index_id
})
});
const result = await response.json();
if (result.ok) {
resultDiv.textContent = result.data.context;
} else {
resultDiv.innerHTML = `<div style="color: red;">Error: ${result.error}</div>`;
}
} catch (error) {
resultDiv.innerHTML = `<div style="color: red;">Error: ${error.message}</div>`;
}
}
</script>
</body>
</html>
Advanced: Context Caching
Copy
import fs from 'fs/promises';
import path from 'path';
import crypto from 'crypto';
class CachedHarvestClient extends HarvestContextClient {
constructor(apiKey, cacheDir = '.harvest_cache', cacheTTLHours = 24) {
super(apiKey);
this.cacheDir = cacheDir;
this.cacheTTL = cacheTTLHours * 60 * 60 * 1000; // Convert to milliseconds
}
async ensureCacheDir() {
try {
await fs.mkdir(this.cacheDir, { recursive: true });
} catch (error) {
console.error('Failed to create cache directory:', error);
}
}
getCacheKey(indexId, query) {
const content = `${indexId}:${query}`;
return crypto.createHash('md5').update(content).digest('hex');
}
getCachePath(cacheKey) {
return path.join(this.cacheDir, `${cacheKey}.json`);
}
async readCache(cacheKey) {
const cachePath = this.getCachePath(cacheKey);
try {
const data = await fs.readFile(cachePath, 'utf-8');
const cached = JSON.parse(data);
const age = Date.now() - cached.timestamp;
if (age < this.cacheTTL) {
console.log(`✅ Cache hit (age: ${Math.round(age / 1000 / 60)} minutes)`);
return cached.context;
} else {
console.log(`⚠️ Cache expired`);
return null;
}
} catch (error) {
// Cache miss or read error
return null;
}
}
async writeCache(cacheKey, context) {
await this.ensureCacheDir();
const cachePath = this.getCachePath(cacheKey);
try {
const data = JSON.stringify({
timestamp: Date.now(),
context: context
});
await fs.writeFile(cachePath, data);
console.log(`💾 Cached result`);
} catch (error) {
console.error('⚠️ Cache write error:', error);
}
}
async getContext(indexId, query, useCache = true) {
const cacheKey = this.getCacheKey(indexId, query);
// Try cache first
if (useCache) {
const cachedContext = await this.readCache(cacheKey);
if (cachedContext) {
return cachedContext;
}
}
// Fetch from API
const context = await super.getContext(indexId, query);
if (context) {
await this.writeCache(cacheKey, context);
}
return context;
}
}
Environment Variables
Create a.env
file:
Copy
# .env
HARVEST_API_KEY=your-api-key-here
Package.json
Copy
{
"name": "harvest-context-client",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node main.js"
},
"dependencies": {
"node-fetch": "^3.3.0",
"dotenv": "^16.0.3"
}
}