लाइव चैंपियनशिप स्टैंडिंग्स टेबल बनाएँ
एक छोटे कैशिंग प्रॉक्सी के ज़रिए अपनी वेबसाइट पर MotoGP, Moto2 या Moto3 राइडर्स चैंपियनशिप दिखाएँ, ताकि आपकी RapidAPI कुंजी ब्राउज़र से दूर रहे।
10 मिनट में पढ़ें
स्टैंडिंग्स टेबल न्यूज़ साइट, फ़ैन ब्लॉग और क्लब पेजों पर सबसे आम MotoGP विजेट है। यह गाइड इसे दो हिस्सों में बनाती है:
- प्रॉक्सी: एक छोटा सर्वर endpoint जो आपकी कुंजी रखता है और रिस्पॉन्स कैश करता है।
- विजेट: सादा HTML और JavaScript जो प्रॉक्सी से टेबल रेंडर करता है।
1. प्रॉक्सी
ब्राउज़र को आपकी RapidAPI कुंजी कभी नहीं दिखनी चाहिए, इसलिए पेज आपके अपने endpoint से बात करता है। इस उदाहरण में Node.js 18+ और Express इस्तेमाल हुए हैं; यही 30 लाइनें Netlify, Vercel या Cloudflare फ़ंक्शन के रूप में भी चलती हैं।
// server.js — npm install express
import express from "express";
const HOST = "motogp-api-championship-data-statistics.p.rapidapi.com";
const KEY = process.env.RAPIDAPI_KEY;
if (!KEY) throw new Error("RAPIDAPI_KEY is not set");
const CATEGORIES = new Set(["MOTOGP", "MOTO2", "MOTO3"]);
const TTL_MS = 60 * 60 * 1000; // 1 hour
const cache = new Map();
async function cached(path) {
const hit = cache.get(path);
if (hit && Date.now() - hit.at < TTL_MS) return hit.body;
const res = await fetch(`https://${HOST}${path}`, {
headers: { "X-RapidAPI-Key": KEY, "X-RapidAPI-Host": HOST },
});
if (!res.ok) throw new Error(`Upstream ${res.status}`);
const body = await res.json();
cache.set(path, { at: Date.now(), body });
return body;
}
const app = express();
app.get("/api/standings", async (req, res) => {
const category = String(req.query.category ?? "MOTOGP").toUpperCase();
if (!CATEGORIES.has(category)) return res.status(400).json({ error: "Unknown category" });
try {
const { data: season } = await cached("/seasons/latest");
const { data } = await cached(`/standings/seasons/${season.year}/riders?category=${category}`);
res.set("Cache-Control", "public, max-age=300").json({ season: season.year, category, rows: data });
} catch (err) {
res.status(502).json({ error: "Standings are unavailable right now" });
}
});
app.use(express.static("public"));
app.listen(3000, () => console.log("http://localhost:3000"));
दो बातें अहम हैं:
- इनपुट वैलिडेट करें। सिर्फ़ तीन जानी-पहचानी कैटेगरी आगे भेजी जाती हैं, ताकि कोई आपके प्रॉक्सी से मनमाने endpoints पर आपका कोटा खर्च न कर सके।
- कैश करें। हर कैटेगरी के लिए प्रति घंटा एक अपस्ट्रीम कॉल सभी विज़िटर्स को सेवा देती है।
2. विजेट
<!-- public/index.html -->
<div class="standings">
<div role="tablist">
<button data-category="MOTOGP" aria-selected="true">MotoGP</button>
<button data-category="MOTO2">Moto2</button>
<button data-category="MOTO3">Moto3</button>
</div>
<table>
<caption></caption>
<thead>
<tr><th>Pos</th><th>Rider</th><th>Team</th><th>Wins</th><th>Pts</th></tr>
</thead>
<tbody></tbody>
</table>
</div>
<script type="module">
const tbody = document.querySelector(".standings tbody");
const caption = document.querySelector(".standings caption");
function cell(text) {
const td = document.createElement("td");
td.textContent = text; // textContent, never innerHTML, for data from an API
return td;
}
async function load(category) {
caption.textContent = "Loading…";
const res = await fetch(`/api/standings?category=${category}`);
if (!res.ok) {
caption.textContent = "Standings are unavailable right now.";
tbody.replaceChildren();
return;
}
const { season, rows } = await res.json();
caption.textContent = `${season} ${category} riders' championship`;
tbody.replaceChildren(
...rows.map((r) => {
const tr = document.createElement("tr");
tr.append(
cell(r.position),
cell(`#${r.rider_number} ${r.rider_name}`),
cell(r.team_name),
cell(r.wins),
cell(r.total_points),
);
return tr;
}),
);
}
document.querySelectorAll("[data-category]").forEach((button) => {
button.addEventListener("click", () => {
document.querySelectorAll("[data-category]").forEach((b) => b.setAttribute("aria-selected", b === button));
load(button.dataset.category);
});
});
load("MOTOGP");
</script>
RAPIDAPI_KEY=... node server.js चलाएँ और http://localhost:3000 खोलें।
विविधताएँ
- लीडर से अंतर।
rows[0].total_points - r.total_pointsवाला एक कॉलम जोड़ें। - टीम चैंपियनशिप। दूसरे रूट को
/standings/seasons/{year}/teamsपर इंगित करें; पंक्तियों मेंteam_nameऔरtotal_pointsहोते हैं। - मैन्युफ़ैक्चरर।
/standings/seasons/{year}/manufacturersmanufacturer_nameवाली पंक्तियाँ लौटाता है। - स्टैटिक साइट। बिल्ड स्टेप (Astro, Next.js, Hugo) में स्टैंडिंग्स लाएँ और हर रेस वीकेंड के बाद दोबारा बिल्ड करें; प्रॉक्सी की ज़रूरत ही नहीं।