İçeriğe geç
Örnekler

Şehir kartı

Bir il yaz: havası, benzin fiyatı, son 24 saatin depremleri ve namaz vakitleri tek kartta, her satırda kaynağı ve saatiyle.

  1. Anahtar al. Ücretsiz kayıt, ayda 1.000 kredi. Anahtarı panelde üretirsin; ak_live_ ile başlar.
  2. Dosyayı al. Aşağıdan kopyala ya da indir: sehir.mjs. Node 18 ya da üstü yeter, paket yok.
  3. Çalıştır. KILAVUZ_ANAHTAR=ak_live_… node sehir.mjs. Sayfa localhost:3000’de açılır.

Tek dosya, olduğu gibi çalışır:

// Şehir kartı: seçilen ilde bugünün havası, benzin fiyatı, son 24 saatin depremleri
// ve namaz vakitleri; dört istek, her satırda kaynağı ve güncelleme saati.
// Node 18+, paket yok.  KILAVUZ_ANAHTAR=ak_live_… node sehir.mjs  →  http://localhost:3000
// Anahtar yalnız bu sunucuda durur; tarayıcı aşağıdaki izinli uçlara gider, sunucu Kılavuz'a iletir.
import { createServer } from 'node:http';

const API = 'https://api.kilavuzapi.com';
const ANAHTAR = process.env.KILAVUZ_ANAHTAR;
if (!ANAHTAR) throw new Error('KILAVUZ_ANAHTAR tanımlı değil (anahtar: kilavuzapi.com/panel)');
const IZINLI = ['/v1/hava/durum', '/v1/akaryakit/fiyat', '/v1/deprem/son', '/v1/takvim/namaz'];
const PORT = process.env.PORT ?? 3000;

createServer(async (istek, yanit) => {
  const { pathname, search } = new URL(istek.url, 'http://yerel');
  if (!IZINLI.includes(pathname)) return yanit.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }).end(SAYFA);
  let govde = '';
  for await (const parca of istek) if ((govde += parca).length > 10_000) return yanit.writeHead(413).end();
  try {
    const r = await fetch(API + pathname + search, {
      method: istek.method,
      headers: { authorization: `Bearer ${ANAHTAR}`, 'content-type': 'application/json' },
      body: istek.method === 'POST' ? govde : undefined,
    });
    yanit.writeHead(r.status, { 'content-type': 'application/json; charset=utf-8' }).end(await r.text());
  } catch {
    yanit.writeHead(502, { 'content-type': 'application/json; charset=utf-8' }).end('{"hata":"Kılavuz API\'sine ulaşılamadı"}');
  }
}).listen(PORT, '127.0.0.1', () => console.log(`http://localhost:${PORT}`));

const SAYFA = `<!doctype html>
<html lang="tr">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Şehir kartı</title>
<style>
  body { font: 16px/1.5 system-ui, sans-serif; max-width: 26rem; margin: 40px auto; padding: 0 16px; color: #16181c; }
  form { display: flex; gap: 8px; }
  input { flex: 1; padding: 8px 10px; font: inherit; border: 1px solid #c3c7cd; border-radius: 6px; }
  button { padding: 8px 14px; font: inherit; border: 0; border-radius: 6px; background: #16181c; color: #fff; cursor: pointer; }
  dl { margin: 24px 0 0; border: 1px solid #dfe2e6; border-radius: 10px; }
  dl div { padding: 12px 16px; }
  dl div + div { border-top: 1px solid #dfe2e6; }
  dt { font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: #6b7280; }
  dd { margin: 2px 0 0; font-size: 18px; }
  small { display: block; font-size: 12px; color: #6b7280; }
</style>
<h1 id="baslik">Şehir kartı</h1>
<form id="form">
  <input name="il" value="İstanbul" aria-label="İl">
  <button>Göster</button>
</form>
<dl id="kart"></dl>
<script>
  const form = document.getElementById('form');
  const kart = document.getElementById('kart');
  const sayi = (n) => n.toLocaleString('tr-TR', { maximumFractionDigits: 2 });
  const saat = (iso) => new Date(iso).toLocaleString('tr-TR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Istanbul' });
  const al = (yol) => fetch(yol).then((r) => r.json()).catch(() => ({ hata: 'yanıt alınamadı' }));

  function satir(baslik, j, metin, kaynak) {
    const div = document.createElement('div');
    const dt = document.createElement('dt');
    const dd = document.createElement('dd');
    const alt = document.createElement('small');
    dt.textContent = baslik;
    dd.textContent = j.hata ?? metin(j);
    alt.textContent = j.hata ? '' : kaynak + (j.guncelleme ? ' · ' + saat(j.guncelleme) : '') + (j.bayat ? ' · eski veri' : '');
    div.append(dt, dd, alt);
    kart.append(div);
  }

  form.onsubmit = async (e) => {
    e.preventDefault();
    const il = encodeURIComponent(form.il.value.trim());
    kart.textContent = '';
    const [hava, yakit, deprem, namaz] = await Promise.all([
      al('/v1/hava/durum?il=' + il),
      al('/v1/akaryakit/fiyat?urun=benzin&il=' + il),
      al('/v1/deprem/son?saat=24&il=' + il),
      al('/v1/takvim/namaz?il=' + il),
    ]);
    document.getElementById('baslik').textContent = hava.hata ? 'Şehir kartı' : hava.il;

    satir('Hava', hava, (h) => sayi(h.anlik.sicaklikC) + ' °C, ' + h.anlik.durum
      + ' · yarın ' + sayi(h.gunluk[1].enDusukC) + '–' + sayi(h.gunluk[1].enYuksekC) + ' °C', 'MET Norway');
    satir('Benzin 95', yakit, (y) => {
      const o = y.ozet.find((x) => x.urun === 'Kurşunsuz Benzin 95 Oktan') ?? y.ozet[0];
      return o ? sayi(o.ortalama) + ' ₺/L ortalama · en düşük ' + sayi(o.enDusuk) : 'Bu ilde fiyat yok';
    }, 'EPDK');
    satir('Deprem · son 24 saat', deprem, (d) => {
      if (!d.depremler.length) return 'Kayıt yok';
      const b = d.depremler.reduce((m, x) => (x.buyukluk > m.buyukluk ? x : m));
      return d.toplam + ' deprem, en büyüğü ' + sayi(b.buyukluk) + ' (' + (b.ilce ?? b.yer) + ')';
    }, 'AFAD');
    const VAKIT = { imsak: 'İmsak', gunes: 'Güneş', ogle: 'Öğle', ikindi: 'İkindi', aksam: 'Akşam', yatsi: 'Yatsı' };
    satir('Namaz vakitleri', namaz, (n) => Object.entries(VAKIT)
      .map(([k, ad]) => ad + ' ' + n.vakitler[k]).join(' · '), 'Diyanet açılarıyla hesap');
  };
  form.requestSubmit();
</script>
`;

Kullandığı uçlar

  • GET /v1/hava/durum1 kredi
  • GET /v1/akaryakit/fiyat1 kredi
  • GET /v1/deprem/son1 kredi
  • GET /v1/takvim/namazücretsiz

Anahtar tarayıcıya inmez. Dosya küçük bir sunucu: sayfayı verir, tarayıcının isteğini anahtarı ekleyerek Kılavuz’a iletir. Yalnız IZINLI listesindeki uçlar geçer. Kendi uygulamana taşırken de anahtarı sunucuda tut. Uçların ayrıntısı dokümanda.

Öteki örnekler