JavaScript ile Altın Fiyatı API'si: Node.js, TypeScript ve Next.js
JavaScript'te altın fiyatı API'si: async/await ile fetch, TypeScript yanıt tipleri, önbellekli Express veya Next.js route'u ve API anahtarının güvenli kullanımı.
JavaScript ile altın fiyatı API'si: ilk istek
JavaScript'ten bir altın fiyatı API'sini çağırmak tek bir fetch çağrısı gerektirir; ancak canlı ortamdaki bir entegrasyon tiplere, hata yönetimine, bir önbelleğe ve API anahtarı için güvenli bir yere de ihtiyaç duyar. Bu yazı tüm bunları, değerli metaller, endüstriyel metaller, enerji, para birimleri ve kripto paralar için bir JSON REST API'si olan MetalAPI ile kuruyor: önce sade bir Node.js betiği, ardından tipli bir TypeScript istemcisi, son olarak da anahtarı açığa çıkarmadan altın fiyatını frontend'inize sunan küçük bir Express veya Next.js route'u.
Node.js 18 ve sonrası fetch ile birlikte gelir; bu nedenle bir HTTP kütüphanesine gerek yoktur. Panelde bir anahtar oluşturun (anahtarlar mk_live_ ile başlar), onu bir .env dosyasına METALAPI_KEY=mk_live_... olarak yazın ve betiği node --env-file=.env gold.mjs ile çalıştırın. Dosyayı Node.js 20.6 ve sonrası okur; daha eski sürümlerde bunun yerine değişkeni shell'inizde export edin.
const params = new URLSearchParams({ base: "USD", currencies: "XAU" });
const res = await fetch(`https://metalapi.com/api/v1/latest?${params}`, {
headers: { "X-API-Key": process.env.METALAPI_KEY },
signal: AbortSignal.timeout(10_000),
});
const data = await res.json();
if (!data.success) throw new Error(`MetalAPI ${data.error.code}: ${data.error.info}`);
const price = data.rates[`${data.base}XAU`];
console.log(`Gold: ${price} ${data.base} per troy ounce`);
console.log(`Price time: ${new Date(data.timestamp * 1000).toISOString()}`);Dokümantasyondaki örnek değerlerle rates.USDXAU değeri 3997.89 olur: bir troy ons altının baz para birimi cinsinden fiyatı. Aynı nesne yaklaşık 0.00025 olan rates.XAU değerini de içerir; bu ters kurdur, yani dolar başına troy ons altın. Yanlışlıkla bunu göstermek klasik altın fiyatı hatasıdır. base değerini EUR yaparsanız anahtar EURXAU olur; gram fiyatı için unit=gram ekleyin. timestamp, isteğinizin değil fiyat verisinin zamanıdır ve Unix saniyesi cinsindendir.
Altın fiyatı API yanıtı için TypeScript tipleri
Yanıt yapıları küçük ve kararlıdır; bu da onları tiplemeyi kolaylaştırır. Başarılı yanıtlarda success: true bulunur. Başarısız yanıtlarda ise success: false ve sayısal bir code, bir type ve bir info mesajı taşıyan bir error nesnesi bulunur; dolayısıyla success üzerine kurulan bir ayrımlı birleşim (discriminated union), TypeScript'in ikisi arasında tip daraltması yapmasını sağlar. Bu istemci ayrıca hataları, istek limiti yanıtlarındaki Retry-After değerini koruyan tipli bir hataya dönüştürür:
const API = "https://metalapi.com/api/v1";
export interface RateLimit {
limit: number;
remaining: number;
used: number;
reset: number; // Unix saniyesi
reset_date: string;
plan: string;
}
export interface LatestResponse {
success: true;
timestamp: number; // fiyat verisinin zamanı, Unix saniyesi
date: string;
base: string;
unit?: string; // unit troy_oz değilse bulunur
rates: Record<string, number>; // "USDXAU": fiyat, "XAU": ters kur
rate_limit: RateLimit;
}
export interface TimeframeResponse {
success: true;
start_date: string;
end_date: string;
base: string;
rates: Record<string, Record<string, number>>; // YYYY-MM-DD ile anahtarlanır
rate_limit: RateLimit;
}
export interface ErrorResponse {
success: false;
error: { code: number; type: string; info: string; upgrade_url?: string };
}
export class MetalApiError extends Error {
code: number;
type: string;
retryAfter?: number;
constructor(code: number, type: string, info: string, retryAfter?: number) {
super(`MetalAPI ${code} (${type}): ${info}`);
this.name = "MetalApiError";
this.code = code;
this.type = type;
this.retryAfter = retryAfter;
}
}
export async function metalapi<T extends { success: true }>(
path: string,
params: Record<string, string> = {},
): Promise<T> {
const res = await fetch(`${API}/${path}?${new URLSearchParams(params)}`, {
headers: { "X-API-Key": process.env.METALAPI_KEY ?? "" },
signal: AbortSignal.timeout(10_000),
});
const body = (await res.json().catch(() => null)) as T | ErrorResponse | null;
if (body === null) throw new MetalApiError(res.status, "http_error", res.statusText);
if (body.success === false) {
const retryAfter = Number(res.headers.get("Retry-After")) || undefined;
throw new MetalApiError(body.error.code, body.error.type, body.error.info, retryAfter);
}
return body;
}
export async function goldPrice(base = "USD", unit = "troy_oz") {
const data = await metalapi<LatestResponse>("latest", { base, currencies: "XAU", unit });
return { price: data.rates[`${data.base}XAU`], base: data.base, unit, asOf: new Date(data.timestamp * 1000) };
}await goldPrice("EUR", "gram") gram başına euro fiyatını zaman damgasıyla birlikte döndürür; metalapi<TimeframeResponse>("timeframe", { start_date, end_date, currencies: "XAU" }) ise istek başına Free planda en fazla 30, ücretli planlarda 365 günün kapanış fiyatlarını döndürür. Mesaja göre değil, her zaman err.code değerine göre dallanın. Yalnızca 104 (dakika başına limit; retryAfter saniye sonra), 500, 503 ve ağ hatalarını yeniden deneyin; bu başarısız istekler ücretlendirilmez. Diğer kodlar ise bir düzeltme gerektirir: 101 veya 102 eksik ya da geçersiz bir anahtar, 105 tükenmiş bir aylık kota, 106 ise planınızın içermediği bir endpoint anlamına gelir.
Sunucu mu, tarayıcı mı: API anahtarının yeri
İstemci tarafı JavaScript'teki her şey herkese açıktır. Bir React paketindeki (bundle), satır içi bir betikteki veya NEXT_PUBLIC_ ya da VITE_ önekli bir ortam değişkenindeki anahtarı her ziyaretçi tarayıcının geliştirici araçlarında okuyabilir ve her sayfa görüntüleme isteklerinizden birini harcar. Altın fiyatını kullanıcıların önüne getirmenin üç yolu vardır:
- Kendi sunucu route'unuz (önerilir). Tarayıcı sizin endpoint'inizi çağırır; sunucunuz da MetalAPI'yi anahtarla çağırır ve sonucu önbelleğe alır. Ne kadar trafik alırsanız alın, kullanım önbellek yenileme başına bir istekte kalır.
- Tarayıcıda alan adıyla sınırlandırılmış bir anahtar. Panelde bir anahtarı kendi alan adlarınızla sınırlandırabilirsiniz;
OriginveyaRefererdeğeri eşleşmeyen tarayıcı istekleri107hatasıyla ve ücretlendirilmeden reddedilir. Bu, diğer web sitelerinin anahtarı kendi ziyaretçilerinin tarayıcılarında kullanmasını engeller, ancak anahtarı bir betiğe kopyalayan birini engellemez:OriginveyaRefereriçermeyen isteklere her zaman izin verilir. Bunun için ayrı bir anahtar kullanın, asla ana anahtarınızı değil. Ayrıntılar kimlik doğrulama rehberinde yer alır. - Gömülebilir bir widget. Basit bir fiyat gösterimi için bir widget ne anahtar ne de kod gerektirir ve widget sayfa görüntülemeleri kotanızdan düşülmez.
Express'te önbellekli bir altın fiyatı API route'u
Bir sunucu route'unun önbelleğe ihtiyacı vardır. Her plan fiyatları sabit bir aralıkla yeniler (Free planda günlük, Lite'ta 30 dakikada bir, Standard'da 10 dakikada bir, Advanced ve Pro'da 60 saniyede bir); bu nedenle daha erken sormak aynı sayıları döndürür ve yalnızca kota harcar. Bu route her para birimi ve birim için sonucu 10 dakika önbelleğe alır, eşzamanlı isteklerin tek bir upstream çağrıyı paylaşmasını sağlar ve MetalAPI'ye ulaşılamazsa son geçerli fiyatı sunmaya devam eder:
// npm install express, ardından: METALAPI_KEY=mk_live_... npx tsx server.ts
import express from "express";
import { goldPrice } from "./metalapi";
const TTL_MS = 10 * 60_000; // Standard plan: fiyatlar 10 dakikada bir güncellenir
const CURRENCIES = new Set(["USD", "EUR", "GBP"]);
const UNITS = new Set(["troy_oz", "gram"]);
type Quote = Awaited<ReturnType<typeof goldPrice>>;
const cache = new Map<string, { quote: Quote; expires: number }>();
const inflight = new Map<string, Promise<Quote>>();
function cachedGold(base: string, unit: string): Promise<Quote> {
const key = `${base}:${unit}`;
const hit = cache.get(key);
if (hit && Date.now() < hit.expires) return Promise.resolve(hit.quote);
let pending = inflight.get(key); // single flight: anahtar başına tek upstream çağrı
if (!pending) {
pending = goldPrice(base, unit)
.then((quote) => {
cache.set(key, { quote, expires: Date.now() + TTL_MS });
return quote;
})
.catch((err) => {
if (!hit) throw err;
cache.set(key, { quote: hit.quote, expires: Date.now() + 60_000 }); // eski veri, 1 dk sonra tekrar dene
return hit.quote;
})
.finally(() => inflight.delete(key));
inflight.set(key, pending);
}
return pending;
}
const app = express();
app.get("/api/gold", async (req, res) => {
const base = String(req.query.currency ?? "USD").toUpperCase();
const unit = String(req.query.unit ?? "troy_oz");
if (!CURRENCIES.has(base) || !UNITS.has(unit)) {
res.status(400).json({ error: "Unsupported currency or unit" });
return;
}
try {
res.set("Cache-Control", "public, max-age=60").json(await cachedGold(base, unit));
} catch (err) {
console.error(err);
res.status(503).json({ error: "Gold price temporarily unavailable" });
}
});
app.listen(3000, () => console.log("http://localhost:3000/api/gold?currency=EUR&unit=gram"));İzin listesi güvenlik kadar kotanız için de önemlidir. Her para birimi ve birim kombinasyonu, yenileme başına bir isteğe mal olan ayrı bir önbellek kaydıdır; bu nedenle günün her saatinde sıcak tutulan altı kombinasyon ayda yaklaşık 26.800 istek tutar. Listeyi sayfalarınızın gösterdikleriyle sınırlı tutun ya da PHP ve WordPress eğitiminde olduğu gibi birkaç para birimini tek bir istekte alıp yerel olarak dönüştürün. Önbellek işlem belleğinde tutulur; birden fazla örnek (instance) veya serverless fonksiyon kullanıyorsanız onu Redis'e ya da platformunuzun önbelleğine taşıyın.
Frontend bundan sonra MetalAPI'yi değil, her zaman sizin route'unuzu çağırır:
<p>Gold: <strong id="gold">…</strong> <small id="gold-time"></small></p>
<script type="module">
const res = await fetch("/api/gold?currency=EUR&unit=gram");
if (res.ok) {
const q = await res.json();
const money = new Intl.NumberFormat(undefined, { style: "currency", currency: q.base });
document.getElementById("gold").textContent = `${money.format(q.price)} per gram`;
document.getElementById("gold-time").textContent = `as of ${new Date(q.asOf).toLocaleString()}`;
}
</script>Aynı route Next.js'te
Next.js App Router'da aynı işi bir Route Handler görür ve elle yazılmış önbelleğin yerini Next.js veri önbelleği alabilir. İstemciyi lib/metalapi.ts olarak kaydedin ve anahtarı yalnızca sunucuda bulunması için .env.local dosyasında, NEXT_PUBLIC_ öneki olmadan METALAPI_KEY olarak saklayın:
import type { ErrorResponse, LatestResponse } from "@/lib/metalapi";
export async function GET() {
try {
const res = await fetch("https://metalapi.com/api/v1/latest?currencies=XAU,XAG", {
headers: { "X-API-Key": process.env.METALAPI_KEY ?? "" },
next: { revalidate: 600 }, // Standard plan: yanıtı 10 dakika boyunca yeniden kullan
});
const data = (await res.json()) as LatestResponse | ErrorResponse;
if (data.success) {
return Response.json({ gold: data.rates.USDXAU, silver: data.rates.USDXAG, timestamp: data.timestamp });
}
console.error("MetalAPI error", data.error.code, data.error.info);
} catch (err) {
console.error(err);
}
return Response.json({ error: "Prices temporarily unavailable" }, { status: 503 });
}next: { revalidate: 600 }, upstream yanıtını en fazla 10 dakika saklar ve istekler arasında paylaşır. Next.js yalnızca HTTP 200 durumundaki yanıtları saklar; bu nedenle bir MetalAPI hatası asla önbelleğe alınmaz. Uygulamanızda Cache Components etkinse fetch çağrısını 'use cache' ile işaretlenmiş bir yardımcı fonksiyona taşıyın ve ömrünü bunun yerine cacheLife ile belirleyin.
Sonraki adımlar
Bir anahtar almak için ücretsiz bir hesap oluşturun. Free plan, günlük güncellemelerle ayda 100 istek içerir ve kredi kartı gerektirmez; bu, yukarıdaki her şeyi geliştirip test etmeye yeter. Route'unuz canlıya çıktığında planı güncelliğe ve hacme göre seçin: 10 dakikalık bir önbellek kaydı ayda yaklaşık 4.500 istek tutar; bu da Standard planın 10.000 isteğine sığar. Fiyatlandırma sayfası tüm planları karşılaştırır; Python ile altın fiyatı API'si ise aynı API'yi betikler, pandas ve grafikler için ele alır.
Sık sorulan sorular
Altın fiyatı API'sini doğrudan tarayıcıdan çağırabilir miyim?
Evet. API, farklı kaynaklardan gelen (cross-origin) isteklere yanıt verir; bu nedenle fetch bir web sayfasından çalışır. Alan adlarınızla sınırlandırılmış bir anahtar kullanın ve ziyaretçilerin anahtarı yine de okuyabileceğini, her sayfa görüntülemenin de bir isteğe mal olduğunu unutmayın. Önbellekli bir sunucu route'u daha ucuzdur ve anahtarı gizli tutar.
Sayfam neden altın fiyatı yerine 0,00025 gösteriyor?
Ters kur olan rates.XAU değerini okuyorsunuz. rates.USDXAU değerini ya da baz para birimi değişiyorsa rates[base + "XAU"] değerini okuyun. Örnek değerlerle 1 ÷ 0,0002501319 yine 3.997,89 sonucunu verir.
JavaScript'te altın fiyatını euro cinsinden veya gram başına nasıl alırım?
base=EUR ve unit=gram gönderin. Fiyat bu durumda gram başına euro cinsinden rates.EURXAU olur ve yanıt unit: "gram" alanını içerir. unit ayrıca troy_oz (varsayılan), kilogram, ounce, pound, metric_ton ve short_ton değerlerini de kabul eder. Altın için avoirdupois ons olan ounce kullanmaktan kaçının.
Altın fiyatını ne sıklıkla yenilemeliyim?
En fazla planınızın güncelleme aralığı başına bir kez: Free planda günlük, Lite'ta saatte bir (30 dakikada bir yenilemek 1.000 isteklik kotaya karşı ayda yaklaşık 1.490 istek tutar), Standard'da 10 dakikada bir. Spot altının New York saatiyle cuma 17:00'den pazar 17:00'ye kadar işlem görmediği hafta sonu boyunca fiyatlar sabit kalır.
Sorgulama yapmadan altın fiyatlarını gerçek zamanlı alabilir miyim?
Pro ve üzeri planlarda /stream, fiyat güncellemelerini Server-Sent Events üzerinden iletir; böylece /latest endpoint'ini hiç sorgulamanız gerekmez. Altının 4.000 $'ı geçmesi gibi eşik mantığı için webhook'lu fiyat alarmları (Advanced ve üzeri planlar), koşul gerçekleştiğinde sunucunuzu çağırır.
Kendi verilerinizle deneyin
Ücretsiz bir hesap oluşturun ve ilk isteğinizi iki dakikadan kısa sürede gönderin. Ayda 100 istek, kredi kartı gerekmez.
Okumaya devam edin
XAU/USD Ne Demek? XAU, XAG, XPT ve XPD Ne Anlama Gelir
XAU/USD ne demek? Altının neden ISO 4217 döviz kodu olduğunu, XAG, XPT ve XPD'nin anlamını ve fiyat ve API verilerinde kur yönünün nasıl okunduğunu öğrenin.
Ücretsiz Altın Fiyatı API'si: Ayda 100 İstekle Neler Yapılır
Ücretsiz altın fiyatı API'si açıkça anlatıldı: MetalAPI Free planı neler içerir, ayda 100 istek önbellek ve toplu sorguyla nasıl yeter, ne zaman yükseltmeli?
Python ile Altın Fiyatı API'si: Veri Çekme, Önbellek ve Grafik
Python'da altın fiyatı API'si kullanın: requests ile canlı fiyatları alın, hataları ve yeniden denemeleri yönetin, önbelleğe alın, pandas ile grafik çizin.