Add frontend-optimized aggregation endpoints
- Add GET /mints/{mint_id}/profile - full mint profile in one request
- Add GET /mints/cards - lightweight cards for directory/grid views
- Add GET /mints/{mint_id}/metrics - timeseries metrics for charts
- Add GET /analytics/activity - ecosystem activity timeline
- Add POST /mints/compare - side-by-side mint comparison
- Add GET /mints/rankings - ranked leaderboards by trust/uptime/latency/reviews
- Add GET /mints/{mint_id}/similar - find similar mints
- Add GET /mints/recommended - use-case based recommendations
- Add GET /mints/{mint_id}/compatibility - wallet compatibility info
- Add GET /wallets/{wallet_name}/recommended-mints - wallet-specific recommendations
- Add GET /mints/{mint_id}/risk - risk assessment and flags
- Update OpenAPI documentation for all new endpoints
- Fix review rating parsing from content field
- Fix trust score calculation to include parsed ratings
This commit is contained in:
@@ -32,7 +32,17 @@ import {
|
||||
getPopularMints,
|
||||
getMintStats,
|
||||
getMintAvailability,
|
||||
getMintCard
|
||||
getMintCard,
|
||||
getMintProfile,
|
||||
getMintCards,
|
||||
getMintMetrics,
|
||||
compareMints,
|
||||
getMintRankings,
|
||||
getSimilarMints,
|
||||
getRecommendedMints,
|
||||
getMintCompatibility,
|
||||
getWalletRecommendedMints,
|
||||
getMintRisk
|
||||
} from '../services/AnalyticsService.js';
|
||||
|
||||
const router = Router();
|
||||
@@ -249,6 +259,103 @@ router.get('/trending', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/cards
|
||||
* Get lightweight mint cards for directory/list views
|
||||
*/
|
||||
router.get('/cards', (req, res) => {
|
||||
try {
|
||||
const { status, limit = 100, offset = 0, sort_by = 'trust_score', sort_order = 'desc' } = req.query;
|
||||
|
||||
const cards = getMintCards({
|
||||
status,
|
||||
limit: Math.min(parseInt(limit) || 100, 500),
|
||||
offset: parseInt(offset) || 0,
|
||||
sortBy: sort_by,
|
||||
sortOrder: sort_order
|
||||
});
|
||||
|
||||
res.json({
|
||||
cards,
|
||||
total: cards.length,
|
||||
limit: Math.min(parseInt(limit) || 100, 500),
|
||||
offset: parseInt(offset) || 0
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting mint cards:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /mints/compare
|
||||
* Compare multiple mints side by side
|
||||
*/
|
||||
router.post('/compare', (req, res) => {
|
||||
try {
|
||||
const { mint_ids } = req.body;
|
||||
|
||||
if (!mint_ids || !Array.isArray(mint_ids) || mint_ids.length === 0) {
|
||||
return res.status(400).json({ error: 'mint_ids array required' });
|
||||
}
|
||||
|
||||
if (mint_ids.length > 10) {
|
||||
return res.status(400).json({ error: 'Maximum 10 mints can be compared' });
|
||||
}
|
||||
|
||||
const comparison = compareMints(mint_ids);
|
||||
res.json(comparison);
|
||||
} catch (error) {
|
||||
console.error('[API] Error comparing mints:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/rankings
|
||||
* Get ranked mint leaderboard
|
||||
*/
|
||||
router.get('/rankings', (req, res) => {
|
||||
try {
|
||||
const { by = 'trust', period = '30d', limit = 50 } = req.query;
|
||||
|
||||
const validBy = ['trust', 'uptime', 'latency', 'reviews'];
|
||||
const validPeriods = ['7d', '30d', '90d'];
|
||||
|
||||
const rankings = getMintRankings(
|
||||
validBy.includes(by) ? by : 'trust',
|
||||
validPeriods.includes(period) ? period : '30d',
|
||||
Math.min(parseInt(limit) || 50, 100)
|
||||
);
|
||||
|
||||
res.json(rankings);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting rankings:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/recommended
|
||||
* Get recommended mints by use case
|
||||
*/
|
||||
router.get('/recommended', (req, res) => {
|
||||
try {
|
||||
const { use_case = 'general', limit = 10 } = req.query;
|
||||
|
||||
const validUseCases = ['general', 'mobile', 'high_volume', 'privacy'];
|
||||
const recommendations = getRecommendedMints(
|
||||
validUseCases.includes(use_case) ? use_case : 'general',
|
||||
Math.min(parseInt(limit) || 10, 50)
|
||||
);
|
||||
|
||||
res.json(recommendations);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting recommendations:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// BY-URL ROUTES (must come BEFORE :mint_id routes)
|
||||
// ==========================================
|
||||
@@ -906,4 +1013,93 @@ router.get('/:mint_id/card', resolveMintMiddleware, (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/:mint_id/profile
|
||||
* Full mint profile - aggregated data in one request
|
||||
*/
|
||||
router.get('/:mint_id/profile', resolveMintMiddleware, async(req, res) => {
|
||||
try {
|
||||
const profile = await getMintProfile(req.mint.mint_id);
|
||||
if (!profile) {
|
||||
return res.status(404).json({ error: 'Mint not found' });
|
||||
}
|
||||
|
||||
// Record pageview
|
||||
recordPageview(req.mint.mint_id, {
|
||||
sessionId: req.headers['x-session-id'],
|
||||
userAgent: req.headers['user-agent'],
|
||||
referer: req.headers['referer']
|
||||
});
|
||||
|
||||
res.json(profile);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting mint profile:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/:mint_id/metrics
|
||||
* Mint metrics timeseries for charts
|
||||
*/
|
||||
router.get('/:mint_id/metrics', resolveMintMiddleware, (req, res) => {
|
||||
try {
|
||||
const { range = '7d' } = req.query;
|
||||
const validRanges = ['7d', '30d', '90d'];
|
||||
const timeRange = validRanges.includes(range) ? range : '7d';
|
||||
|
||||
const metrics = getMintMetrics(req.mint.mint_id, timeRange);
|
||||
res.json(metrics);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting mint metrics:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/:mint_id/similar
|
||||
* Find similar mints
|
||||
*/
|
||||
router.get('/:mint_id/similar', resolveMintMiddleware, (req, res) => {
|
||||
try {
|
||||
const { limit = 5 } = req.query;
|
||||
const similar = getSimilarMints(
|
||||
req.mint.mint_id,
|
||||
Math.min(parseInt(limit) || 5, 20)
|
||||
);
|
||||
res.json(similar);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting similar mints:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/:mint_id/compatibility
|
||||
* Wallet compatibility info
|
||||
*/
|
||||
router.get('/:mint_id/compatibility', resolveMintMiddleware, (req, res) => {
|
||||
try {
|
||||
const compatibility = getMintCompatibility(req.mint.mint_id);
|
||||
res.json(compatibility);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting compatibility:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /mints/:mint_id/risk
|
||||
* Risk assessment and flags
|
||||
*/
|
||||
router.get('/:mint_id/risk', resolveMintMiddleware, (req, res) => {
|
||||
try {
|
||||
const risk = getMintRisk(req.mint.mint_id);
|
||||
res.json(risk);
|
||||
} catch (error) {
|
||||
console.error('[API] Error getting risk assessment:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user