# TypeScript ile Sağlık API'si Oluşturma

> Eğitim: Kendi tıbbi veritabanınız olmadan hasta kayıtları oluşturan, kan basıncı okumalarını FHIR R4 gözlemleri olarak saklayan, bunları geri okuyan, hataları eşleyen ve webhook'ları doğrulayan bir TypeScript Express API'si.

Source: https://developers.anpheros.com/tr/guides/healthcare-api-typescript

**Bu eğitim, Express ile TypeScript'te bir kan basıncı takip uygulamasının arka uç API'sini oluşturur: kayıt olma, kullanıcının tıbbi kaydını oluşturur, okumalar kodlanmış HL7 FHIR R4 gözlemleri olarak saklanır, uygulama bunları geri okur ve bir webhook uç noktası kendi tıbbi veritabanınız olmadan yeni veriler hakkında bilgi verir.** API'niz ürününüze özgü olanları (kullanıcılar, oturumlar, ayarlar) saklar. Tıbbi veriler, geçmişi, onayı ve kaynağı, [TypeScript SDK](https://developers.anpheros.com/tr/guides/sdks) aracılığıyla çağırdığınız Anpheros'ta bulunur.

## Mimari

```
 mobile / web app ──► your API (Express, TypeScript) ──► Anpheros (FHIR R4 record per patient)
                       │  users, sessions, settings        │  observations, conditions, documents,
                       │  user id → patient id              │  provenance, consent, audit
                       ◄──────────── webhooks ──────────────┘
```

Veritabanınız her kullanıcı için fazladan bir sütun depolar: Anpheros hasta kimlikleri. Klinik her şey API'den geçer, bu nedenle kodlanmış, sürümlenmiş ve herhangi bir FHIR sistemi veya hastanın izin verdiği diğer uygulamalar tarafından okunabilir durumdadır. [Tıbbi uygulama arka ucu ve veritabanı](https://developers.anpheros.com/tr/guides/medical-app-backend) bölümü bu ayrımı ayrıntılı olarak açıklar.

## Başlamadan Önce

- Node.js 18 veya daha yeni sürüm.
- [platform.anpheros.com/dashboard](https://platform.anpheros.com/dashboard/) adresinden bir sandbox anahtarı (`sk_test_…`) (**Bir sandbox anahtarı alın**). Anahtarı yalnızca sunucuda saklayın; uygulamaya asla ulaşmamalıdır.

```bash
mkdir bp-api && cd bp-api
npm init -y && npm pkg set type=module
npm install express @anpheros/sdk
npm install -D typescript tsx @types/express @types/node
export ANPHEROS_KEY=sk_test_…
```

## Adım 1: İstemci ve kullanıcı deponuz

```ts
// server.ts
import express from 'express';
import { Anpheros, AnpherosError, apiKey, verifyWebhookSignature } from '@anpheros/sdk';

const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });
const app = express();

// Your own user table. In production this is your database; the only medical link is patientId.
type User = { id: string; email: string; patientId: string };
const users = new Map<string, User>();

// Stand-in for your real authentication (session cookie, JWT…): it must set the signed-in user.
function currentUser(req: express.Request): User {
  const user = users.get(req.header('x-user-id') ?? '');
  if (!user) throw new HttpError(401, 'not signed in');
  return user;
}

class HttpError extends Error {
  constructor(readonly status: number, message: string) { super(message); }
}
```

## Adım 2: Kayıt işlemi tıbbi kaydı oluşturur

Biri kaydolduğunda, Anpheros'ta hastasını oluşturun ve kendi kullanıcı kimliğinizi `identifiers` içine yerleştirin, böylece kayıt her zaman sizin tarafınızdan bulunabilir:

```ts
app.post('/signup', express.json(), async (req, res, next) => {
  try {
    const { email, given, family, birthDate } = req.body;
    const userId = crypto.randomUUID();
    const patient = await anpheros.patients.create(
      { given, family, birth_date: birthDate, identifiers: [{ system: 'https://bp.example/user', value: userId }] },
      { author_type: 'patient' },
    );
    users.set(userId, { id: userId, email, patientId: patient.id });
    res.status(201).json({ userId });
  } catch (e) { next(e); }
});
```

Anpheros'tan gelen yanıt, projenize ait bir `id` ve FHIR referansıyla birlikte yeni hastadır:

```json
{"id": "27296656-c2ba-4970-8424-1dcd91163e0a", "given": "Ioana", "family": "Marin", "birth_date": "1979-04-12", "gender": "female",
 "identifiers": [{"system": "https://bp.example/user", "value": "u_8f2c"}], "updated_at": "2026-10-12T20:16:51.143Z",
 "fhir": "Patient/27296656-c2ba-4970-8424-1dcd91163e0a"}
```

## Adım 3: Bir okuma kaydetme

Uygulama `{systolic, diastolic, measuredAt}` gönderir. API'niz bunu doğrular ve iki bileşeniyle birlikte LOINC `85354-9` olan bir kan basıncı gözlemi depolar:

```ts
app.post('/readings', express.json(), async (req, res, next) => {
  try {
    const user = currentUser(req);
    const { systolic, diastolic, measuredAt } = req.body;
    if (![systolic, diastolic].every((v) => Number.isFinite(v) && v > 20 && v < 300)) {
      throw new HttpError(400, 'systolic and diastolic must be numbers in mmHg');
    }
    const obs = await anpheros.observations.create(user.patientId, {
      code: '85354-9',
      category: 'vital-signs',
      effective_at: measuredAt ?? new Date().toISOString(),
      components: [
        { code: '8480-6', value: systolic, unit: 'mm[Hg]' },
        { code: '8462-4', value: diastolic, unit: 'mm[Hg]' },
      ],
      author_type: 'patient',
    }, { source_system: 'bp-app' });
    res.status(201).json({ id: obs.id, measuredAt: obs.effective_at });
  } catch (e) { next(e); }
});
```

Anpheros'un depoladığı ve döndürdüğü:

```json
{"id": "78188270-e65e-49bd-89d0-e776226e9614", "patient": "27296656-…", "code": "85354-9", "system": "http://loinc.org",
 "display": "Blood pressure panel", "category": "vital-signs", "effective_at": "2026-10-10T08:30:00Z",
 "components": [{"code": "8480-6", "system": "http://loinc.org", "value": 138.0, "unit": "mm[Hg]"},
                {"code": "8462-4", "system": "http://loinc.org", "value": 88.0, "unit": "mm[Hg]"}],
 "status": "final", "updated_at": "2026-10-12T20:16:51.153Z", "fhir": "Observation/78188270-…"}
```

SDK, her oluşturma işlemiyle birlikte bir `Idempotency-Key` gönderir, böylece ağ hatası sonrası yeniden deneme okumayı iki kez kaydetmez. `author_type: 'patient'` ve `source_system` okumanın kaynağına gider: bir doktor, başka bir uygulama veya bir yapay zeka modeli daha sonra kişinin bunu evde sizin uygulamanızla ölçtüğünü anlayabilir.

## Adım 4: Okumaları Geri Oku

```ts
app.get('/readings', async (req, res, next) => {
  try {
    const user = currentUser(req);
    const page = await anpheros.observations.list(user.patientId, {
      code: '85354-9',
      from: typeof req.query.from === 'string' ? req.query.from : undefined,
      limit: 50,
    });
    res.json({
      readings: page.data.map((o) => ({
        id: o.id,
        measuredAt: o.effective_at,
        systolic: o.components.find((c) => c.code === '8480-6')?.value,
        diastolic: o.components.find((c) => c.code === '8462-4')?.value,
      })),
      next: page.next_cursor,
    });
  } catch (e) { next(e); }
});
```

API'niz, uygulamanızın istediği şekli döndürür. Saklanan veriler standart kalır. Kullanıcı kimliği `currentUser` tarafından kontrol edildiği için, bir kullanıcı asla başka bir kullanıcının hasta kimliğini isteyemez.

## Adım 5: Hatalar

Anpheros hataları `AnpherosError` ile birlikte `status`, `type`, `message`, `field` ve bir `requestId` olarak gelir. Doğrulama hatalarını uygulamaya iletin ve diğerlerini gizleyin:

```ts
app.use((err: unknown, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
  if (err instanceof HttpError) return res.status(err.status).json({ error: err.message });
  if (err instanceof AnpherosError && err.status === 400) {
    return res.status(400).json({ error: err.message, field: err.field });
  }
  console.error(err instanceof AnpherosError ? `anpheros ${err.status} ${err.type} request=${err.requestId}` : err);
  res.status(502).json({ error: 'medical record service unavailable, try again' });
});
```

Örneğin, tarihi olmayan bir okuma Anpheros tarafından `{"error": {"type": "invalid", "message": "Field required (at effective_at)", "field": "effective_at"}}` ile reddedilir. SDK, oran sınırları (`429`) ve sunucu hataları gibi durumları siz görmeden önce yeniden dener. `requestId`'ü günlüğe kaydedin ve destekle iletişime geçerseniz bunu belirtin. Tam liste [Hatalar](https://developers.anpheros.com/tr/guides/errors) bölümünde yer almaktadır.

## Adım 6: Webhook ile Yeni Verilerden Haberdar Olun

Okumalar başka yerlerden de gelebilir: aynı kayda yazan bir klinik, bir laboratuvar raporu, kişinin bağladığı başka bir uygulama. Bir kez bir uç nokta kaydedin:

```bash
curl -X POST https://platform.anpheros.com/v1/webhooks -H "Authorization: Bearer $ANPHEROS_KEY" \
     -H "Content-Type: application/json" \
     -d '{"url": "https://bp.example/webhooks/anpheros", "events": ["resource.created", "consent.revoked"]}'
```

Yanıt, bir kez gösterilen bir `secret` (`whsec_…`) içerir. Güvenmeden önce her teslimatı ham gövdeye karşı doğrulayın:

```ts
app.post('/webhooks/anpheros', express.raw({ type: 'application/json' }), async (req, res) => {
  const ok = await verifyWebhookSignature({
    secret: process.env.ANPHEROS_WEBHOOK_SECRET!,
    header: req.header('anpheros-signature'),
    body: req.body as Buffer,
  });
  if (!ok) return res.status(400).end();
  const event = JSON.parse((req.body as Buffer).toString('utf8'));
  // Events carry ids and versions, not clinical data: fetch what you need, then update caches or notify.
  console.log(event.type, event.data);
  res.status(204).end();
});

app.listen(3000, () => console.log('bp-api on http://localhost:3000'));
```

Olay türleri `resource.created`, `resource.updated`, `resource.deleted`, `consent.granted`, `consent.revoked`, `document.finalized` ve `ping`'dur. Teslimatlar imzalanır, yeniden denenir ve yeniden oynatılabilir ([Webhook'lar](https://developers.anpheros.com/tr/guides/webhooks)).

## Çalıştırın

```bash
npx tsx server.ts
curl -X POST localhost:3000/signup -H 'content-type: application/json' \
     -d '{"email":"ioana@example.com","given":"Ioana","family":"Marin","birthDate":"1979-04-12"}'
# {"userId":"…"}
curl -X POST localhost:3000/readings -H 'content-type: application/json' -H 'x-user-id: <userId>' \
     -d '{"systolic":138,"diastolic":88,"measuredAt":"2026-10-10T08:30:00Z"}'
curl localhost:3000/readings -H 'x-user-id: <userId>'
```

Bir şey makinenizden ayrılmadan önce, `x-user-id` yer tutucusunu gerçek kimlik bilgilerinizle değiştirin.

## İleriye Gitmek

- **Zaten kaydı olan kişiler.** Bir API anahtarı, projenizin oluşturduğu hastalara ulaşır. Başka uygulamalar, klinikler veya laboratuvarlar tarafından toplanan bir kişinin mevcut kaydına bağlanmak için OAuth ve onların onayını kullanın: [SMART on FHIR ile hasta onayını uygulama](https://developers.anpheros.com/tr/guides/smart-on-fhir-backend).
- **İhtiyacınız olduğunda Strict FHIR.** `anpheros.fhir.search`, `create`, `transaction`, `everything` ve `summary`, aynı kimliklerle size [FHIR R4 API](https://developers.anpheros.com/tr/guides/store-medical-records-fhir) sunar.
- **Yapay Zeka özellikleri.** `anpheros.context.build`, bir model için kaynak etiketli bir bağlam hazırlar: [FHIR arka ucu ile bir Yapay Zeka sağlık uygulaması oluşturma](https://developers.anpheros.com/tr/guides/build-ai-healthcare-app).
- **Üretim.** Üretim anahtarları (`sk_live_…`), imzalanmış bir DPA'ya sahip doğrulanmış kuruluşlara verilir; [Fiyatlandırma](https://developers.anpheros.com/tr/guides/pricing) ve [Sınırlar ve hız sınırları](https://developers.anpheros.com/tr/guides/limits) bölümlerine bakın.

## Sıkça Sorulan Sorular

### Tıbbi veriler için kendi veritabanıma ihtiyacım var mı?
Tıbbi verilerin kendisi için hayır. Veritabanınız kullanıcıları, oturumları ve ürün ayarlarını, ayrıca her kullanıcı için hasta kimliğini saklar. Gözlemler, durumlar, ilaçlar, belgeler, bunların geçmişi ve kimin yazdığı FHIR kaydında saklanır.

### Mobil uygulama Anpheros'u doğrudan çağırabilir mi?
API anahtarıyla hayır: anahtar projenizin her hastasına ulaşır ve sunucunuzda kalmalıdır. Mobil uygulama, kişinin kendi kaydı için verdiği bir OAuth jetonu ile Anpheros'u doğrudan çağırabilir, [Flutter ile sağlık uygulaması nasıl oluşturulur](https://developers.anpheros.com/tr/guides/healthcare-app-flutter) bölümünde olduğu gibi.

### Hangi çerçeve ile çalışır?
Herhangi biri. SDK yalnızca `fetch` gerektirir, bu nedenle Express, Fastify, Hono, NestJS, Next.js rota işleyicileri, Deno veya Bun'da çalışır.

## İlgili Konular

- [Sağlık API'si](https://developers.anpheros.com/tr/guides/healthcare-api): Bir sağlık API'sinde nelere dikkat etmeli ve Anpheros API'sine genel bir bakış
- [Tıbbi Veri API'si](https://developers.anpheros.com/tr/guides/medical-data-api): Her tür tıbbi verinin nereye gittiği
- [FHIR R4 Kullanarak Tıbbi Kayıtların Nasıl Saklanacağı](https://developers.anpheros.com/tr/guides/store-medical-records-fhir)
- [Webhook'lar](https://developers.anpheros.com/tr/guides/webhooks) ve [Hatalar](https://developers.anpheros.com/tr/guides/errors)
- [Tıbbi Uygulama Arka Ucu ve Veritabanı](https://developers.anpheros.com/tr/guides/medical-app-backend)
