Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
كيفية بناء واجهة برمجة تطبيقات للرعاية الصحية باستخدام TypeScript
دليل تعليمي: واجهة برمجة تطبيقات Express بلغة TypeScript تنشئ سجلات المرضى، تخزن قراءات ضغط الدم كملاحظات FHIR R4، تقرأها مرة أخرى، تعيّن الأخطاء، وتتحقق من خطافات الويب — دون الحاجة لقاعدة بيانات طبية خاصة بك.
يبني هذا البرنامج التعليمي واجهة برمجة التطبيقات الخلفية لتطبيق تتبع ضغط الدم باستخدام TypeScript مع Express: يقوم التسجيل بإنشاء السجل الطبي للمستخدم، ويتم تخزين القراءات كملاحظات HL7 FHIR R4 مرمزة، وتقرأها التطبيق مرة أخرى، ويستمع نقطة نهاية خطاف الويب إلى البيانات الجديدة، دون الحاجة إلى قاعدة بيانات طبية خاصة بك. تحتفظ واجهة برمجة التطبيقات الخاصة بك بما هو خاص بمنتجك (المستخدمون، الجلسات، الإعدادات). البيانات الطبية وتاريخها والموافقة عليها ومصدرها تعيش في Anpheros، والتي تتصل بها عبر TypeScript SDK.
البنية
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 ──────────────┘
يخزن نظام قاعدة البيانات الخاص بك عمودًا إضافيًا لكل مستخدم: معرف المريض الخاص بهم في Anpheros. كل شيء سريري يمر عبر الـ API، لذلك يتم ترميزه، وإصداره، وقراءته بواسطة أي نظام FHIR أو بواسطة التطبيقات الأخرى للمريض التي يوافق عليها. يشرح الواجهة الخلفية لقاعدة بيانات التطبيق الطبي هذا التقسيم بالتفصيل.
قبل البدء
- Node.js 18 أو أحدث.
- مفتاح بيئة اختبار (
sk_test_…) من platform.anpheros.com/dashboard (احصل على مفتاح بيئة اختبار). احتفظ به على الخادم فقط؛ يجب ألا يصل أبدًا إلى التطبيق.
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_…
الخطوة 1: العميل ومتجر المستخدم الخاص بك
// 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); }
}
الخطوة 2: إنشاء السجل الطبي عند التسجيل
عندما يقوم شخص ما بالتسجيل، قم بإنشاء مريض له في Anpheros وضع معرف المستخدم الخاص بك في identifiers، حتى يمكن العثور على السجل دائمًا من جانبك:
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 هي المريض الجديد، مع id ينتمي إلى مشروعك ومرجع FHIR الخاص به:
{"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"}
الخطوة 3: تخزين قراءة
يرسل التطبيق {systolic, diastolic, measuredAt}. يقوم واجهة برمجة التطبيقات (API) الخاصة بك بالتحقق منها وتخزين ملاحظة واحدة لضغط الدم، LOINC 85354-9، مع مكوناتها:
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 بتخزينه وإرجاعه:
{"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 Idempotency-Key مع كل عملية إنشاء، لذلك لا تؤدي إعادة المحاولة بعد خطأ في الشبكة إلى تخزين القراءة مرتين. تذهب author_type: 'patient' و source_system إلى مصدر القراءة: يمكن للطبيب، أو تطبيق آخر، أو نموذج ذكاء اصطناعي أن يخبر لاحقًا أن الشخص قام بالقياس في المنزل باستخدام تطبيقك.
الخطوة 4: قراءة القراءات مرة أخرى
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) الشكل الذي يريده تطبيقك. تظل البيانات المخزنة قياسية. نظرًا لأن معرف المستخدم يتم التحقق منه بواسطة currentUser، لا يمكن لمستخدم واحد أبدًا طلب معرف مريض لمستخدم آخر.
الخطوة 5: الأخطاء
تصل أخطاء Anpheros كـ AnpherosError مع status، type، message، field و requestId. قم بتمرير أخطاء التحقق إلى التطبيق وإخفاء الباقي:
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' });
});
على سبيل المثال، يتم رفض قراءة بدون تاريخ بواسطة Anpheros مع {"error": {"type": "invalid", "message": "Field required (at effective_at)", "field": "effective_at"}}. يتم إعادة محاولة حدود المعدل (429) وأخطاء الخادم بواسطة SDK قبل أن تراها. قم بتسجيل requestId واقتبسه إذا اتصلت بالدعم. القائمة الكاملة موجودة في الأخطاء.
الخطوة 6: تلقي بيانات جديدة عبر خطاف الويب (Webhook)
يمكن أن تصل القراءات أيضًا من أماكن أخرى: عيادة تكتب إلى نفس السجل، تقرير مختبر، تطبيق آخر قام الشخص بتوصيله. قم بتسجيل نقطة نهاية مرة واحدة:
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"]}'
يحتوي الرد على secret (whsec_…)، يتم عرضه مرة واحدة. تحقق من كل تسليم مقابل الجسم الخام قبل الوثوق به:
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'));
أنواع الأحداث هي resource.created، resource.updated، resource.deleted، consent.granted، consent.revoked، document.finalized و ping. يتم توقيع عمليات التسليم، وإعادة محاولة، ويمكن إعادة تشغيلها (Webhooks).
تشغيله
npx tsx server.ts
curl -X POST localhost:3000/signup -H 'content-type: application/json' \
-d '{"email":"[email protected]","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>'
استبدل x-user-id بالبيانات الحقيقية للمصادقة الخاصة بك قبل أن يغادر أي شيء جهازك.
للمضي قدمًا
- الأشخاص الذين لديهم سجل بالفعل. يصل مفتاح واجهة برمجة التطبيقات (API) إلى المرضى الذين أنشأ مشروعك لهم سجلات. للاتصال بسجل شخص موجود، تم جمعه بواسطة تطبيقات أو عيادات أو مختبرات أخرى، استخدم OAuth وموافقتهم: كيفية تنفيذ موافقة المريض باستخدام SMART on FHIR.
- FHIR صارم عند الحاجة إليه.
anpheros.fhir.search،create،transaction،everythingوsummaryتمنحك واجهة برمجة تطبيقات FHIR R4 بنفس المعرفات. - ميزات الذكاء الاصطناعي.
anpheros.context.buildتُعد سياقًا مُصنّفًا للمصدر لنموذج: كيفية بناء تطبيق رعاية صحية بالذكاء الاصطناعي مع واجهة خلفية FHIR. - الإنتاج. تُصدر مفاتيح الإنتاج (
sk_live_…) للمنظمات المعتمدة مع اتفاقية حماية بيانات (DPA) موقعة؛ راجع التسعير و الحدود وحدود المعدل.
أسئلة متكررة
هل أحتاج إلى قاعدة بيانات خاصة بي للبيانات الطبية؟
ليس للبيانات الطبية نفسها. تحتفظ قاعدة بياناتك بالمستخدمين والجلسات وإعدادات المنتج، بالإضافة إلى معرف المريض لكل مستخدم. يتم تخزين الملاحظات والحالات والأدوية والمستندات وتاريخها ومن كتبها في سجل FHIR.
هل يمكن للتطبيق المحمول استدعاء Anpheros مباشرة؟
باستخدام مفتاح API، لا: يصل المفتاح إلى كل مريض في مشروعك ويجب أن يبقى على خادمك. يمكن للتطبيق المحمول استدعاء Anpheros مباشرة باستخدام رمز OAuth الذي منحه الشخص لسجله الخاص، كما هو موضح في كيفية بناء تطبيق رعاية صحية باستخدام Flutter.
مع أي إطار عمل يعمل هذا؟
أي إطار عمل. يحتاج SDK فقط إلى fetch، لذا فهو يعمل في Express و Fastify و Hono و NestJS ومعالجات مسارات Next.js و Deno أو Bun.
ذات الصلة
- واجهة برمجة تطبيقات الرعاية الصحية: ما الذي تبحث عنه في واجهة برمجة تطبيقات الرعاية الصحية، ونظرة عامة على واجهة برمجة تطبيقات Anpheros.
- واجهة برمجة تطبيقات البيانات الطبية: أين تذهب كل أنواع البيانات الطبية.
- كيفية تخزين السجلات الطبية باستخدام FHIR R4
- خطافات الويب و الأخطاء
- الواجهة الخلفية وقاعدة بيانات التطبيق الطبي
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card