API & Integration
Integration Guide
Practical examples for integrating pRPC and building custom features
Building a Custom Dashboard
Create a custom dashboard showing specific metrics:
'use client';
import { useAllPNodes, useNetworkStats } from '@/lib/hooks';
import { Card } from '@/components/ui/card';
export function CustomDashboard() {
const { data: nodes } = useAllPNodes();
const { data: stats } = useNetworkStats();
// Filter high-performance nodes
const topNodes = nodes
?.filter(n => n.healthScore > 90)
.slice(0, 10);
// Calculate custom metric
const avgStorageUsage = nodes?.reduce(
(acc, node) => acc + node.storage.usagePercentage, 0
) / (nodes?.length || 1);
return (
<div>
<h1>My Custom Dashboard</h1>
<Card>
<h2>Top 10 Nodes (Health > 90)</h2>
{topNodes?.map(node => (
<div key={node.publicKey}>
{node.moniker}: {node.healthScore}
</div>
))}
</Card>
<Card>
<h2>Network Metrics</h2>
<p>Total Nodes: {stats?.totalNodes}</p>
<p>Avg Storage Usage: {avgStorageUsage.toFixed(1)}%</p>
</Card>
</div>
);
}Filtering and Searching Nodes
import { useAllPNodes } from '@/lib/hooks';
import { useState, useMemo } from 'react';
export function NodeSearch() {
const { data: nodes } = useAllPNodes();
const [search, setSearch] = useState('');
const [minHealth, setMinHealth] = useState(0);
// Filter and sort nodes
const filteredNodes = useMemo(() => {
if (!nodes) return [];
return nodes
.filter(node =>
node.moniker.toLowerCase().includes(search.toLowerCase()) &&
node.healthScore >= minHealth
)
.sort((a, b) => b.healthScore - a.healthScore);
}, [nodes, search, minHealth]);
return (
<div>
<input
type="text"
placeholder="Search by moniker..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<input
type="range"
min="0"
max="100"
value={minHealth}
onChange={(e) => setMinHealth(Number(e.target.value))}
/>
<span>Min Health: {minHealth}</span>
<div>
Found {filteredNodes.length} nodes
</div>
</div>
);
}Building Custom Analytics
import { useAllPNodes } from '@/lib/hooks';
import { useMemo } from 'react';
export function GeoAnalytics() {
const { data: nodes } = useAllPNodes();
const analytics = useMemo(() => {
if (!nodes) return null;
// Group by country
const byCountry = nodes.reduce((acc, node) => {
const country = node.location.country;
if (!acc[country]) {
acc[country] = {
count: 0,
totalStorage: 0,
avgHealth: 0,
};
}
acc[country].count++;
acc[country].totalStorage += node.storage.total;
acc[country].avgHealth += node.healthScore;
return acc;
}, {} as Record<string, any>);
// Calculate averages
Object.values(byCountry).forEach((data: any) => {
data.avgHealth /= data.count;
});
// Sort by count
const sorted = Object.entries(byCountry)
.sort(([, a]: any, [, b]: any) => b.count - a.count);
return sorted;
}, [nodes]);
return (
<div>
<h2>Nodes by Country</h2>
{analytics?.map(([country, data]: [string, any]) => (
<div key={country}>
<strong>{country}</strong>: {data.count} nodes,
Avg Health: {data.avgHealth.toFixed(1)}
</div>
))}
</div>
);
}Real-time Monitoring
Set up monitoring with custom refresh intervals:
import { useAllPNodes } from '@/lib/hooks';
import { useEffect } from 'react';
export function RealTimeMonitor() {
const { data: nodes, refetch } = useAllPNodes();
// Custom refresh interval (30 seconds)
useEffect(() => {
const interval = setInterval(() => {
refetch();
}, 30000);
return () => clearInterval(interval);
}, [refetch]);
// Monitor for critical nodes
const criticalNodes = nodes?.filter(node =>
node.uptime < 95 ||
node.storage.usagePercentage > 90 ||
node.performance.avgLatency > 200
);
return (
<div>
<h2>Critical Nodes Alert</h2>
{criticalNodes?.length === 0 ? (
<p>All nodes healthy</p>
) : (
criticalNodes?.map(node => (
<div key={node.publicKey} className="alert">
{node.moniker}:
{node.uptime < 95 && ' Low uptime'}
{node.storage.usagePercentage > 90 && ' High storage'}
{node.performance.avgLatency > 200 && ' High latency'}
</div>
))
)}
</div>
);
}Custom Data Export
import { useAllPNodes } from '@/lib/hooks';
export function CustomExport() {
const { data: nodes } = useAllPNodes();
const exportFilteredNodes = () => {
// Filter nodes
const filtered = nodes?.filter(n => n.healthScore > 80);
// Create custom CSV
const headers = ['Moniker', 'Country', 'Health', 'Uptime'];
const rows = filtered?.map(n => [
n.moniker,
n.location.country,
n.healthScore,
n.uptime,
]);
const csv = [
headers.join(','),
...rows.map(row => row.join(',')),
].join('\n');
// Download
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'high-health-nodes.csv';
a.click();
};
return (
<button onClick={exportFilteredNodes}>
Export High Health Nodes
</button>
);
}Building Alerts
import { useAllPNodes } from '@/lib/hooks';
import { useEffect } from 'react';
export function NodeAlerts() {
const { data: nodes } = useAllPNodes();
useEffect(() => {
if (!nodes) return;
// Check for nodes with issues
nodes.forEach(node => {
if (node.uptime < 90) {
console.warn(`Low uptime alert: ${node.moniker}`);
// Could send notification here
}
if (node.storage.usagePercentage > 95) {
console.error(`Storage critical: ${node.moniker}`);
// Could trigger email/webhook
}
});
}, [nodes]);
return <div>Monitoring {nodes?.length} nodes...</div>;
}Integration with External APIs
Combine XandScan data with external services:
import { useAllPNodes } from '@/lib/hooks';
export async function enrichNodeData(publicKey: string) {
// Get node from XandScan
const client = getPNodeClient();
const node = await client.getPNodeDetails(publicKey);
// Enrich with external data
const geoData = await fetch(
`https://api.ipgeolocation.io/ipgeo?ip=${node.ipAddress}`
).then(r => r.json());
return {
...node,
enriched: {
isp: geoData.isp,
continent: geoData.continent_name,
currency: geoData.currency,
},
};
}Best Practices
- • Use React Query hooks instead of direct PNodeClient calls
- • Leverage useMemo for expensive calculations
- • Respect the 60s cache - don't over-refetch
- • Handle loading and error states properly
- • Use TypeScript for type safety
- • Test with real pNode data before deploying
Next Steps
- • Review API Reference for complete type definitions
- • Check Architecture to understand data flow
- • See Deployment to publish your custom features