diff --git a/src/app/data-api/page.tsx b/src/app/data-api/page.tsx new file mode 100644 index 00000000..22159832 --- /dev/null +++ b/src/app/data-api/page.tsx @@ -0,0 +1,306 @@ +import Link from "next/link"; +import { fetchDataApiSnapshot, GROUP_META, fmtDataValue } from "@/lib/data-api-stats"; +import { DataApiHubTabs } from "@/components/data-api-hub-tabs"; +import { pageMetadata } from "@/lib/page-metadata"; +import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld"; +import { SITE } from "@/data/site"; + +/** + * Hub landing page for the data API vertical: price feeds, token metadata, + * portfolio/wallet indexing, DEX coverage, and NFT data. + * + * Blob-only: loads the materialized bench blobs for each of the 9 data-API + * benchmarks. Never touches Prometheus at render time. Graceful degradation + * if blobs are missing — the page renders the "warming up" state with direct + * bench links, never a 404 or throw. + */ + +const DESCRIPTION = + "Live benchmark rankings for crypto data APIs: price feed latency, token metadata coverage, wallet indexing freshness, DEX chain coverage, and NFT data quality."; + +export const metadata: import("next").Metadata = pageMetadata({ + path: "/data-api", + title: "Best Crypto Data API 2026, ranked by benchmark", + description: DESCRIPTION, +}); + +export const revalidate = 60; + +const BENCH_SLUGS = [ + "aggregator-head-lag", + "metadata-coverage", + "asset-registry-coverage", + "token-quote-coverage", + "indexing-freshness", + "portfolio-chain-coverage", + "wallet-labels-coverage", + "dex-network-coverage", + "nft-collection-metadata", +] as const; + +export default async function DataApiHubPage() { + const snapshot = await fetchDataApiSnapshot(); + + const breadcrumbLd = { + "@context": "https://schema.org", + ...buildBreadcrumbJsonLd([ + { name: "Home", item: SITE.url }, + { name: "Data API benchmarks", item: `${SITE.url}/data-api` }, + ]), + }; + + const itemListLd = { + "@context": "https://schema.org", + "@type": "ItemList", + name: "Crypto data API benchmarks by OpenChainBench", + description: DESCRIPTION, + numberOfItems: BENCH_SLUGS.length, + itemListElement: BENCH_SLUGS.map((slug, i) => ({ + "@type": "ListItem", + position: i + 1, + name: slug, + url: `${SITE.url}/benchmarks/${slug}`, + })), + }; + + return ( +
+