# API havuzu

> Bir projenizin API'sini öteki projelere, başka kiracılara ya da internete anahtarla açın, başka bir projenin API'sini kendi uygulamanızdan çağırın. Havuza uyumlu uygulama yazmak, örnek kodla.

Her ortam kendi ağında çalışır: bir projeniz, başka bir projenin sitesine içeriden ulaşamaz. **API havuzu** bunu denetimli bir kapıyla açar.

- API'sini havuza veren projeye **sağlayıcı**, o API'yi çağıran projeye **tüketici** denir.
- Sağlayıcının ortamı API'sini havuza **uç** olarak ekler.
- Tüketicinin ortamı o uca **bağlanır** ve çağırmak için kendine ait bir **anahtar** alır.
- Kimin bağlanabileceğine sağlayıcı karar verir. Anahtarı platform denetler; sağlayıcı uygulamanın kendi anahtar denetimini yazması gerekmez.

Örnek: `ses-tanima` projeniz bir konuşma tanıma API'si sunuyor; `haber-sitesi` projeniz onu çağırmak istiyor. `ses-tanima`nın ortamı ucu havuza ekler, `haber-sitesi`nin ortamı uca bağlanır. Başka hiçbir ortam bu uca ulaşamaz.

**Kurulumunuza bağlı:** Bu özellik kurulumunuzda açık değilse panelde görünmez; açılmasını istiyorsanız platform yöneticinize sorun.

API havuzu kurulumunuzda açık olsa da her kiracıda açık olmayabilir. Kiracınızda açık değilse panelde **API havuzu** sayfası ve ortamın **API havuzu** sekmesi görünmez; platform yöneticinize başvurun.

## Nasıl işler

1. Sağlayıcı, API'yi sunan ortamın **API havuzu** sekmesinde ucu havuza ekler ve kimin göreceğini seçer.
2. Tüketici, **API havuzu** sayfasında ucu bulur ve kendi ortamını «Bağlan» ile bağlar. Uç onay istiyorsa sağlayıcı onaylar.
3. Bağlantı açılınca tüketicinin ortamına ucun adresi ve anahtarı değişken olarak yazılır. Tüketici ortamını yeniden dağıtır.
4. Tüketicinin uygulaması ucu bu adresten, anahtarla çağırır. Sağlayıcının uygulaması isteği alır ve çağıranı bir istek başlığından tanır.

Uygulamaların bu adımlarda ne yapması gerektiği [Uyumlu bir sağlayıcı yazmak](#uyumlu-bir-saglayici-yazmak) ve [Uyumlu bir tüketici yazmak](#uyumlu-bir-tuketici-yazmak) bölümlerinde, kopyalayıp çalıştırabileceğiniz örnekler [Örnek: iki küçük uygulama](#ornek-iki-kucuk-uygulama) bölümündedir.

## Ucu havuza eklemek

**Ortamın API havuzu sekmesini açın**

Projeler sayfasında API'yi sunan ortamı seçin ve **API havuzu** sekmesine geçin. **Havuza verdiği uçlar** bölümü bu ortamın uçlarını listeler.
**«Ucu havuza ekle»**

Bir **Uç adı** verin (küçük harf, rakam ve tire). Havuzda uç, kiracınızın adı ve bu adla görünür. **Açıklama**ya ucun ne yaptığını ve nasıl çağrıldığını yazın; bağlanacak kişi onu okur.
**Kimin göreceğini seçin**

**Kim görür ve bağlanır** bölümünden görünürlüğü seçin (aşağıda), sonra «Havuza ekle». Ucu sonradan değiştirmek için satırındaki «Ucun ayarları» penceresini açın.

Ucu projenin yazma yetkisi olanlar ekler ve değiştirir. Ucu kiracınızın dışına açmak, dış anahtar oluşturmak ve yenilemek projeyi yönetebilenlerin işidir. Başka ekibin projesindeki ucu silmek için yönetme paylaşımı gerekir.

Uç ortama bağlıdır: ortam yeniden dağıtıldığında uç aynı kalır, adres değişmez. Çok uygulamalı bir ortamda ucun hangi uygulamaya gideceğini ve isterseniz bir yol önekini (`/v1` gibi) seçersiniz.

### Görünürlük

| Görünürlük | Kim görür ve bağlanabilir |
|---|---|
| «Kapalı» | Kimse bağlanamaz; uç havuzda görünmez. Projeyi yönetenler ucu ortamın sekmesinde görmeye devam eder. |
| «Ekip içi» | Yalnız projenin ekibindeki projeler. Ekip yalıtımı açık kiracılarda sunulur. |
| «Kiracı içi» | Kiracınızdaki bütün projeler. |
| «Platform» | Bu platformdaki bütün kiracılar. |
| «İnternet» | İnternetten, anahtarla; hangi adreslerin ulaşacağını siz seçersiniz. Aşağıda: [Ucu internete açmak](#ucu-internete-acmak). |

Başka bir kiracının ya da (ekip yalıtımı açıkken) başka bir ekibin bağlanması varsayılan olarak onay ister: istek gelince size bildirim gider, siz onaylayana kadar bağlantı bekler. Bu onayı ucun ayarlarından projeyi yönetebilenler kapatır.

Görünürlüğü daraltırsanız (örneğin **Kapalı**ya çekerseniz) yeni kapsamın dışında kalan bağlantılar hemen kapanır; panel önce kaç bağlantının etkileneceğini söyler ve onay ister. Kapanan bağlantının sahibine bildirim gider.

Proje başka bir kiracıya ya da ekibe taşınırsa uç projeyle gider ve bağlantılar yeniden denetlenir: yeni yerde kapsam dışında kalan bağlantı kapanır, karşı tarafa bildirim gider. Başka kiracıya taşımada, onayı olmadan kiracı dışına çıkan bağlantı da kapanır; bağlantıyı yeniden isteyip onay alabilirsiniz.

Ekip yalıtımını açarken önizleme, hangi bağlantıların kapanacağını ve hangilerinin onaysız süreceğini gösterir. Onaysız süren bağlantı kesilmez; istemiyorsanız ucun bağlantılarından kapatın.

Projeyi göremeyen biri havuzda ucun adını ve açıklamasını görür; proje ve ortam adının yerinde "Gizli proje" yazar.

## Bir uca bağlanmak

**Havuzda ucu bulun**

Sol menüdeki **API havuzu** sayfası size açık uçları listeler: önce kendi kiracınızınkiler, sonra platforma açılanlar.
**«Bağlan»**

Uç satırında «Bağlan» düğmesine basın ve API'yi çağıracak projeyi ve ortamı seçin. Ortamına yazabildiğiniz bir proje gerekir.
**Yeniden dağıtın**

Bağlantı açılınca ortamınıza iki değişken eklenir: ucun adresi ve anahtarı. Uygulamanız bunları ortam yeniden dağıtılınca görür; panel bunu hatırlatır.

Uç onay istiyorsa bağlantı onaylanana kadar bekler; isteği «İsteği geri çek» ile kaldırabilirsiniz. Onaylanınca size bildirim gider; değişkenler o zaman yazılır.

Bağlantının toplam kullanım sayıları ucu verene görünür; istek içeriği ve adresler görünmez. Ayrıntı: [Ucun kullanımını izlemek](#ucun-kullanimini-izlemek).

Değişkenlerin adları ve uygulamanızın ucu nasıl çağıracağı [Uyumlu bir tüketici yazmak](#uyumlu-bir-tuketici-yazmak) bölümünde. Anahtarın değeri panelde görünmez, yalnız uygulamanıza verilir.

## Bağlantıları yönetmek

Ucun satırındaki «Bağlantılar» penceresi ucunuza kimin bağlı olduğunu gösterir. Başka bir kiracıdan bağlanan ortamın adını yalnız bağlantıyı onaylayabilenler görür; ötekiler o satırda «Başka kiracı» görür.

- «Onayla» ve «Reddet»: bekleyen istekler için.
- «Bağlantıyı kapat»: o ortamın çağrıları hemen reddedilir ve değişkenleri silinir. Aynı bağlantı yeniden açılmaz; gerekirse ortam yeniden bağlanır.
- «Anahtarı yenile»: yeni anahtar hemen geçerli olur ve bağlı ortamın ayarlarına yazılır. Eski anahtarın ne zaman düşeceğini seçersiniz: bağlı ortam yeniden dağıtılınca (kesinti olmaz) ya da hemen (anahtar sızdıysa).

Bağlanan taraf da kendi bağlantısının anahtarını yenileyebilir ve bağlantıyı kapatabilir.

Ucu havuzdan kaldırmak bütün bağlantılarını kapatır; ortama ve uygulamaya dokunmaz.

## Ucun kullanımını izlemek

Kullanımın kendi sayfası var. **API havuzu** sayfasındaki bağlantıdan ya da ortamın **API havuzu** sekmesinde «Kullanım» düğmesinden açılır. Seçtiğiniz uç, bağlantı, anahtar ve aralık sayfanın adresinde durur: adresi paylaştığınız kişi, yetkisi varsa aynı görünümü açar.

Sayfa hangi anahtarın ne kadar istek attığını listeler: `tgz_......xd31` gibi maskeli anahtar, proje, istek sayısı, hatalı istek ve son kullanım. Anahtarın tamamı hiçbir yerde tutulmaz ve gösterilmez. Yenilenen anahtar eskisinden ayrı satırda sayılır, eski anahtarın hâlâ çağrılıp çağrılmadığını buradan görürsünüz. Satıra basınca o anahtarın zaman içindeki dağılımı açılır. Bir anahtarın sonu kayıtlı değilse kimliğiyle görünür; yenileyince maskesi gelir.

Ucu veren proje, ucunu kimin ne kadar kullandığını görür; bunun için projede yazma yetkisi gerekir. Aralığı son bir saatten son bir aya kadar seçersiniz.

- **İstek:** aralıkta gelen istek sayısı.
- **Başarılı:** uygulamanıza giden isteklerin başarı oranı. Uygulamanızın 4xx ve 5xx yanıtları ayrı sayılır.
- **Yanıt süresi:** tipik süre ve yavaş isteklerin süresi. Akan yanıtta yanıtın tamamının süresidir.
- **Reddedilen:** uygulamanıza hiç ulaşmayan çağrılar, sebebiyle birlikte: anahtar, adres ya da yol, sınır.
- **Son istek:** bir süredir çağırmayan bağlantıyı buradan görürsünüz.

Aynı sayılar bağlantı başına da gelir; «Bağlantılar» penceresinde her satırın altında kısa bir özet durur. Anahtarı tanınmayan istek bir bağlantıya yazılamaz, ayrı bir satırda sayılır: uygulamanız hata alıyorsa önce tüketicinin anahtarına bakın.

Bağlanan taraf da kendi kullanımını ve anahtarlarını görür: ortamın **API havuzu** sekmesinde «Bağlandığı uçlar» bölümünde bağlantıda «Kullanım»a basın. Ortamı görebilen herkes bakabilir. Burada yalnız o ortamın bağlantısı sayılır; ucun toplamı ve başka bağlantılar görünmez.

Panel ölçümün kesildiğini ya da sayıların eksik olabileceğini yazıyorsa o süredeki istekler sayılmamıştır. Uygulamanız bundan etkilenmez, önceki sayılar yerinde durur. Göremediğiniz bir proje listede «Başka bir proje» olarak görünür.

Yalnız toplam sayılar tutulur. İstek içeriği, gönderenin adresi, başlıklar ve yol parametreleri tutulmaz.

## Anahtar ömrü

Anahtarlar varsayılan olarak süresizdir. Ucun ayarlarında **Anahtar ömrü** seçebilirsiniz; seçmezseniz havuz ayarındaki ömür geçer.

- Kiracı yöneticisi, **API havuzu** sayfasından kiracının varsayılan ömrünü ve tavanını ayarlar. Hiçbir anahtar tavandan uzun yaşamaz.
- Anahtarın bitişi **Bağlandığı uçlar** bölümünde ve «Bağlantılar» penceresinde yazar.
- Süresi dolan anahtarın bağlantısı kapanır. Kesinti olmaması için süre dolmadan «Anahtarı yenile» ile yenileyin ve ortamı yeniden dağıtın.

## Sınırlar

Ucun sınırlarını ayarlarında siz belirlersiniz: anahtar başına dakikadaki istek sayısı, anlık patlama ve aynı anda süren istek sayısı; uç için isteğin gövdesinin boyutu ve yanıtın en uzun süresi. Varsayılanlar panelde yazar. Bunların üstünde her uçta geçerli üst sınırlar da vardır; ucun ayarlarında yazarlar.

İstek sayısı ya da aynı anda süren istek sınırını aşan çağıran 429 alır; yanıt ne kadar beklemesi gerektiğini söyler. Uzun süren ve akan yanıtlar (yapay zekâ modelleri, ses) bölünmeden, geldikçe iletilir.

## Uyumlu bir sağlayıcı yazmak

Ucu veren uygulama sıradan bir web uygulamasıdır; havuz için ek kitaplık gerekmez.

- **Dinleme:** her Turguz uygulaması gibi `0.0.0.0` adresini ve `PORT` değişkenindeki kapıyı dinler. Havuz, isteği ucun bağlı olduğu uygulamaya iletir.
- **Yol:** tüketici adresin sonuna ne eklerse uygulamanız isteği o yolda alır: `merhaba` eklerse `/merhaba`. Ucun bir yol öneki varsa başına gelir: önek `/v1` ise `/v1/merhaba`.
- **Anahtar:** anahtarı platform denetler; geçersiz anahtarlı istek uygulamanıza ulaşmaz. `Authorization` başlığı uygulamanıza iletilmez. Uygulamanız kendi anahtarını bu başlıkta bekliyorsa havuza açtığınız yollarda bu denetimi kaldırın.
- **Çağıranı tanımak:** havuzdan gelen her istekte `X-Turguz-Tuketici` başlığı vardır. Değeri çağırana göre değişir:

| Çağıran | `X-Turguz-Tuketici` değeri |
|---|---|
| Kiracınızda, bütün kiracıya açık bir projenin ortamı | `<proje adı>/<ortam adı>/<bağlantı>` |
| Kiracınızda, gizli ya da (ekip yalıtımı açıkken) bir ekibin alanındaki projenin ortamı | `kiraci-ici/<bağlantı>` |
| Başka bir kiracıdaki ortam | `kiraci-disi/<bağlantı>` |
| İnternetten, dış anahtarla | `dis/<bağlantı>` |

`<bağlantı>` bağlantıya özgü kısa bir kimliktir ve her biçimde başlığın son parçasıdır: aynı bağlantıdan gelen istekler hep aynı değeri taşır, anahtar yenilense de değişmez; ortam yeniden bağlanırsa yenisi gelir. Çağıranı bu son parçayla tanıyın: projenin görünürlüğü ya da ekip ayarı değişince öteki parçalar kendiliğinden değişir, son parça değişmez. Bu değişiklik için yeniden dağıtım gerekmez. Proje adı `dis`, `kiraci-disi` ya da `kiraci-ici` ise başlık `kiraci-ici/<bağlantı>` biçimindedir. Size kapalı projenin adı ve başka bir kiracıdan çağıranın kiracısı, projesi ve ortamı size bildirilmez. Başlığı çağırana göre kayıt tutmak, kendi payınızı uygulamak ya da yanıtı çağırana göre ayarlamak için kullanın.

İstekle birlikte `X-Turguz-Anahtar` başlığı da gelir: çağıran anahtarın kimliğidir, anahtarın kendisi değil. Anahtar yenilenince değişir, bağlantı aynı kalır. Eski ve yeni anahtarı ayırmak istemiyorsanız bu başlığa bakmanız gerekmez.

**Dikkat:**
Ucunuzu yalnız havuz üzerinden sunacaksanız ortamın erişimini «Dışa kapalı» yapın.

- **İstek gövdesi:** gövdenin uzunluğunu bildiren bir istek ucun sınırını aşıyorsa uygulamanıza gelmeden 413 ile reddedilir. Gövdeyi sonuna kadar okuyup bütün geldiğini doğrulamadan işlemeyin.
- **Akış:** yanıt tamponlanmadan iletilir. Satır satır JSON, sunucu olayları (server-sent events) ya da ses gibi akan bir yanıtı her parçadan sonra boşaltın (flush); tüketici parçaları geldikçe alır. Uzun akışlarda ucun yanıt süresini yeterince uzun seçin.
- **Hatalar:** uygulamanızın döndürdüğü durum kodu ve gövde tüketiciye olduğu gibi gider; JSON bir gövdeyle kısa bir açıklama verin. Uygulamanız cevap veremezse tüketici 502, 503 ya da 504 alır.
- **Ağır işler:** yapay zekâ modeli ya da ses üretimi gibi ağır işlerde aynı anda yapılabilecek iş sayısını uygulamanızda da sınırlayın ve dolunca 429 döndürün; ucun **Eşzamanlı istek** sınırını buna göre seçin.

## Uyumlu bir tüketici yazmak

Tüketici uygulama da sıradan bir web uygulamasıdır ve havuz için ek kitaplık gerekmez. Ucu kendi sunucu tarafındaki kodundan, ortamına yazılan adresle ve anahtarla çağırır. Aşağıdaki kurallar hangi dilde yazarsanız yazın aynıdır; örnek uygulamalar da bunları uygular.

- **Adres ve anahtar:** bağlantı açılınca ortamınıza iki değişken yazılır. Adları ucun adından türer: ad büyük harfe çevrilir, tireler alt çizgi olur.

| Değişken | İçinde |
|---|---|
| `TURGUZ_API_<UÇ ADI>_URL` | Ucun adresi. Sonu `/` ile biter. |
| `TURGUZ_API_<UÇ ADI>_ANAHTARI` | Bu bağlantının anahtarı. |

Örneğin `ornek-api` adlı uç için `TURGUZ_API_ORNEK_API_URL` ve `TURGUZ_API_ORNEK_API_ANAHTARI`. Adları ortamın **API havuzu** sekmesinde, **Bağlandığı uçlar** bölümünden de kopyalayabilirsiniz. Uygulamanız değişkenleri ortam yeniden dağıtılınca görür; değişken yoksa ortam uca bağlı değildir ya da bağlandıktan sonra yeniden dağıtılmamıştır.

- **Çağırmak:** yolu adresin sonuna, başına `/` koymadan ekleyin. Anahtarı her istekte `Authorization: Bearer <anahtar>` başlığıyla gönderin; adrese ya da sorgu satırına yazmayın. İsteğin biçimi:

```bash
curl -H "Authorization: Bearer $TURGUZ_API_ORNEK_API_ANAHTARI" "${TURGUZ_API_ORNEK_API_URL}merhaba"
```

- **Anahtarı sunucuda tutun:** ucu sunucu tarafındaki kodunuzdan çağırın; anahtarı tarayıcıya, mobil uygulamaya ya da günlüğe yazmayın. Adres yalnız bağlı ortamınızdaki uygulamadan çalışır; tarayıcıdan ya da kendi bilgisayarınızdan ulaşılamaz. Turguz dışından çağırmak için ucun internete açılması gerekir.
- **Akış:** akan bir yanıtı parça parça okuyun ve kendi istemcinize geldikçe iletin. İstemcinizin zaman aşımını ucun yanıt süresine göre seçin.
- **Hatalar:** [Hata kodları](#hata-kodlari) tablosuna göre davranın. 429'da bekleyip yeniden deneyin; 502, 503 ve 504'te ucu veren uygulama çalışmıyordur, bir süre sonra yeniden deneyin; 401 sürüyorsa bağlantının durumuna ortamın **API havuzu** sekmesinden bakın.

## Örnek: iki küçük uygulama

Aşağıdaki uygulamalar ek kitaplık istemez. Sağlayıcı, havuza `ornek-api` adıyla eklenen bir uç sunar: `merhaba` yolunda JSON, `akis` yolunda satır satır akan bir yanıt. Tüketici bu uca bağlanan ortamda çalışır; açıldığında iki yolu çağırır ve sonucu gösterir. Her biri ayrı bir projede, kendi ortamında yayına alınır.

### Sağlayıcı

#### Node.js

```javascript
// saglayici.js: havuza uç veren örnek uygulama. Ek kitaplık gerekmez: node saglayici.js
const http = require("node:http");

function json(yanit, kod, veri) {
  yanit.writeHead(kod, { "Content-Type": "application/json; charset=utf-8" });
  yanit.end(JSON.stringify(veri));
}

http.createServer((istek, yanit) => {
  // Havuzdan gelen istekte çağıranın kimliği bu başlıktadır.
  const cagiran = istek.headers["x-turguz-tuketici"] || "bilinmiyor";
  // Bağlantıyı son parçadan tanıyın: öteki parçalar değişebilir.
  const baglanti = cagiran.split("/").pop();
  const yol = new URL(istek.url, "http://uygulama").pathname;

  if (istek.method === "GET" && yol === "/merhaba") {
    return json(yanit, 200, { mesaj: "Merhaba", cagiran, baglanti });
  }
  if (istek.method === "GET" && yol === "/akis") {
    // Satır satır akış: her satır ayrı bir JSON ve yazıldığı anda gider.
    yanit.writeHead(200, { "Content-Type": "application/x-ndjson" });
    yanit.flushHeaders(); // başlıklar ilk satırı beklemeden gider
    let sayi = 0;
    const saat = setInterval(() => {
      sayi += 1;
      yanit.write(JSON.stringify({ satir: sayi }) + "\n");
      if (sayi === 5) {
        clearInterval(saat);
        yanit.end();
      }
    }, 1000);
    yanit.on("close", () => clearInterval(saat)); // tüketici vazgeçerse durur
    return;
  }
  json(yanit, 404, { hata: "yok" });
}).listen(Number(process.env.PORT || 8080), "0.0.0.0");
```

#### Python

```python
# saglayici.py: havuza uç veren örnek uygulama. Yalnız standart kitaplık: python3 saglayici.py
import json
import os
import time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

class Uygulama(BaseHTTPRequestHandler):
    def _json(self, kod, veri):
        govde = json.dumps(veri, ensure_ascii=False).encode()
        self.send_response(kod)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.send_header("Content-Length", str(len(govde)))
        self.end_headers()
        self.wfile.write(govde)

    def do_GET(self):
        # Havuzdan gelen istekte çağıranın kimliği bu başlıktadır.
        cagiran = self.headers.get("X-Turguz-Tuketici", "bilinmiyor")
        # Bağlantıyı son parçadan tanıyın: öteki parçalar değişebilir.
        baglanti = cagiran.rsplit("/", 1)[-1]

        if self.path == "/merhaba":
            return self._json(200, {"mesaj": "Merhaba", "cagiran": cagiran, "baglanti": baglanti})
        if self.path == "/akis":
            # Satır satır akış: her satır ayrı bir JSON ve yazıldığı anda gider.
            self.send_response(200)
            self.send_header("Content-Type", "application/x-ndjson")
            self.end_headers()
            for sayi in range(1, 6):
                self.wfile.write((json.dumps({"satir": sayi}) + "\n").encode())
                self.wfile.flush()
                time.sleep(1)
            return
        self._json(404, {"hata": "yok"})

ThreadingHTTPServer(("0.0.0.0", int(os.environ.get("PORT", "8080"))), Uygulama).serve_forever()
```

### Tüketici

#### Node.js

```javascript
// tuketici.js: ornek-api ucuna bağlanan ortamdaki örnek uygulama. Node 18 ya da sonrası: node tuketici.js
const http = require("node:http");

const ADRES = process.env.TURGUZ_API_ORNEK_API_URL || ""; // sonu "/" ile biter
const ANAHTAR = process.env.TURGUZ_API_ORNEK_API_ANAHTARI || "";

const ACIKLAMA = {
  401: "anahtar geçersiz, süresi dolmuş ya da bağlantı kapatılmış",
  413: "istek gövdesi ucun sınırını aşıyor",
  429: "ucun istek sınırı doldu, biraz sonra yeniden deneyin",
  502: "ucu veren uygulama şu an cevap vermiyor",
  503: "ucu veren uygulama şu an cevap vermiyor",
  504: "ucu veren uygulama zamanında cevap vermedi",
};

async function havuz(yol) {
  // Yol adresin sonuna, başına "/" koymadan eklenir; anahtar her istekte başlıkta gider.
  const cevap = await fetch(ADRES + yol, { headers: { Authorization: `Bearer ${ANAHTAR}` } });
  if (!cevap.ok) throw new Error(`${cevap.status}, ${ACIKLAMA[cevap.status] || (await cevap.text())}`);
  return cevap;
}

http.createServer(async (istek, yanit) => {
  yanit.setHeader("Content-Type", "text/plain; charset=utf-8");
  if (!ADRES || !ANAHTAR) {
    yanit.statusCode = 503;
    return yanit.end("Ortam uca bağlı değil ya da bağlandıktan sonra yeniden dağıtılmadı.\n");
  }
  try {
    const veri = await (await havuz("merhaba")).json();
    const akis = await havuz("akis");
    yanit.write(`${veri.mesaj}, çağıran: ${veri.cagiran}\n`);
    for await (const parca of akis.body) yanit.write(parca); // akan yanıt geldikçe iletilir
    yanit.end();
  } catch (hata) {
    if (!yanit.headersSent) yanit.statusCode = 502;
    yanit.end(`API havuzu: ${hata.message}\n`);
  }
}).listen(Number(process.env.PORT || 8080), "0.0.0.0");
```

#### Python

```python
# tuketici.py: ornek-api ucuna bağlanan ortamdaki örnek uygulama. Yalnız standart kitaplık: python3 tuketici.py
import json
import os
import urllib.error
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

ADRES = os.environ.get("TURGUZ_API_ORNEK_API_URL", "")  # sonu "/" ile biter
ANAHTAR = os.environ.get("TURGUZ_API_ORNEK_API_ANAHTARI", "")

ACIKLAMA = {
    401: "anahtar geçersiz, süresi dolmuş ya da bağlantı kapatılmış",
    413: "istek gövdesi ucun sınırını aşıyor",
    429: "ucun istek sınırı doldu, biraz sonra yeniden deneyin",
    502: "ucu veren uygulama şu an cevap vermiyor",
    503: "ucu veren uygulama şu an cevap vermiyor",
    504: "ucu veren uygulama zamanında cevap vermedi",
}

def havuz(yol):
    # Yol adresin sonuna, başına "/" koymadan eklenir; anahtar her istekte başlıkta gider.
    istek = urllib.request.Request(ADRES + yol, headers={"Authorization": f"Bearer {ANAHTAR}"})
    try:
        return urllib.request.urlopen(istek, timeout=60)
    except urllib.error.HTTPError as hata:
        aciklama = ACIKLAMA.get(hata.code) or hata.read(300).decode("utf-8", "replace")
        raise RuntimeError(f"{hata.code}, {aciklama}") from None

class Uygulama(BaseHTTPRequestHandler):
    def _metin(self, kod, metin):
        self.send_response(kod)
        self.send_header("Content-Type", "text/plain; charset=utf-8")
        self.end_headers()
        self.wfile.write(metin.encode())

    def do_GET(self):
        if not (ADRES and ANAHTAR):
            return self._metin(503, "Ortam uca bağlı değil ya da bağlandıktan sonra yeniden dağıtılmadı.\n")
        try:
            with havuz("merhaba") as cevap:
                veri = json.load(cevap)
            akis = havuz("akis")
        except (RuntimeError, OSError) as hata:
            return self._metin(502, f"API havuzu: {hata}\n")
        with akis:
            self._metin(200, f"{veri['mesaj']}, çağıran: {veri['cagiran']}\n")
            for satir in akis:  # akan yanıt geldikçe, satır satır iletilir
                self.wfile.write(satir)
                self.wfile.flush()

ThreadingHTTPServer(("0.0.0.0", int(os.environ.get("PORT", "8080"))), Uygulama).serve_forever()
```

Denemek için sağlayıcıyı yayına alın ve ucu `ornek-api` adıyla havuza ekleyin; tüketicinin ortamını bu uca bağlayın, yeniden dağıtın ve tüketicinin sitesini açın. Satırlar birer saniye arayla gelir; ilk satırdaki "çağıran" değeri sağlayıcının gördüğü `X-Turguz-Tuketici` başlığıdır.

## Ucu internete açmak

**Kurulumunuza bağlı:** Bu özellik kurulumunuzda açık değilse panelde görünmez; açılmasını istiyorsanız platform yöneticinize sorun.

İnternete açılan uçlar ayrıca bir kurulum ayarına bağlıdır; kapalıysa **İnternet** görünürlüğü seçilemez.

**İnternet** görünürlüğündeki bir uç Turguz dışından, ucun **dış adresi**nden çağrılır. Dış adres ucun satırında yazar ve kopyalanır. Kendi kimlik doğrulamanızı yazmanız gerekmez: anahtarı platform denetler. Dış istemci de anahtarı `Authorization: Bearer <anahtar>` başlığıyla gönderir.

Dış adrese kimin ulaşacağını **Dış adrese kimler ulaşır** bölümünde seçersiniz:

- **Yalnız seçtiğim adres listeleri:** kiracınızın izinli adres listelerinden. Listede olmayan adresten gelen istek reddedilir.
- **Anahtarı olan herkes, her adresten:** ayrıca onay ister. Bazı kurulumlarda bu seçenek yoktur; uç yalnız adres listelerine açılır.

Ucu internete ilk açtığınızda hiçbir şey seçili değildir: bir adres listesi seçene kadar dış adrese hiçbir adres ulaşamaz. «Anahtarı olan herkes» kendiliğinden seçilmez; yalnız siz seçip onaylarsanız açılır.

Dış istemcinize (örneğin mobil uygulamanıza) anahtarı «Dış anahtar oluştur» verir:

- Anahtar **bir kez** gösterilir; kopyalayın ve «Kopyaladım, kapat». Bir daha gösterilmez.
- Her dış anahtar «Bağlantılar» penceresinde kendi adıyla durur ve tek tek kapatılır.
- Yenilerken eski anahtar hemen düşer ya da siz seçerseniz kısa bir süre daha çalışır.
- Uç internetten çıkarılınca dış anahtarlar kapanır.
- Dış anahtar yalnız dış adreste geçer; ortamlarınızın kullandığı iç adreste reddedilir. Ortamlarınızın anahtarı da dış adreste geçmez.
- Dış anahtarı tarayıcıda çalışan koda koymayın: sayfayı açan herkes anahtarı görür. Uç, tarayıcının başka bir siteden yaptığı çağrıya zaten izin vermez.
- Dış adres yalnız `https://` ile çalışır; `http://` ile gelen istek reddedilir.
- Dış adresten dönen yanıt tarayıcıya çerez bırakamaz ve sayfa olarak çalışmaz. Oturum tutan bir uygulamayı buradan sunmayın; dış adres veri içindir.

## Hata kodları

Havuzun kendisinin döndürdüğü kodlar. Sağlayıcı uygulamanın kendi döndürdüğü kodlar tüketiciye olduğu gibi gider.

| Kod | Anlamı |
|---|---|
| 401 | Anahtar yok, yanlış, süresi dolmuş ya da bağlantı kapatılmış. Bağlantı yeni açıldıysa ya da anahtar yeni yenilendiyse kısa bir süre sonra yeniden deneyin. |
| 403 | İnternete açık uçta, isteğin geldiği adres seçilen listelerde değil. |
| 404 | Böyle bir uç yok ya da bu yoldan çağrılamaz (örneğin uç artık internete açık değil). |
| 413 | İsteğin gövdesi ucun sınırını aşıyor. Gövdeyi küçültün ya da sağlayıcıdan sınırı büyütmesini isteyin. |
| 429 | Fazla istek: anahtarın sınırı aşıldı. Yanıtın söylediği kadar bekleyip yeniden deneyin. |
| 502, 503, 504 | Ucu veren uygulama şu an cevap vermiyor (durdurulmuş, yeniden başlıyor ya da yanıtı yetişmedi). Yanıtın gövdesinde kısa bir JSON açıklama gelir. |

İstek havuza hiç ulaşmıyorsa (bağlantı kurulamıyorsa) önce ortamın **API havuzu** sekmesinden bağlantının açık olduğuna bakın; açıksa biraz sonra yeniden deneyin, sürerse platform yöneticinize haber verin.

## Asistanla

Bağlı bir yapay zekâ asistanı ([Asistanınıza bağlayın](/docs/tr/mcp)) havuzu panelle aynı yetkiyle kullanır: uçları listeler, bağlanır, bağlantıları kapatır, anahtarları yeniler ve ucun ayarlarını değiştirir. Bir bağlantıyı kapatmak, ucu kaldırmak, görünürlüğü daraltmak ya da ucu internete açmak gibi adımlarda asistan önce sizin onayınızı ister.

- Bulut asistanı bağlantı isteklerini onaylayamaz; onayı panelden ya da kendi bilgisayarınızdaki asistandan verin.
- Asistan dış anahtarın değerini görmez. Bulut asistanı dış anahtarı oluşturamaz ve yenileyemez; kendi bilgisayarınızdaki asistan oluşturur, ama değeri ona gösterilmez.
- Dış anahtarın değerini panelden alın: projeyi yönetebilen biri anahtarı «Bağlantılar» penceresinde yeniler, yeni değer bir kez gösterilir.
