A unified Islamic API: Quran, Tafsir, Azkar, Hadith, Prayer Times, Hijri Date, and Qibla — with automatic multi-source fallback.
Please select your preferred language below / الرجاء اختيار لغتك المفضلة بالأسفل
Bonyan-API is an enterprise-grade, high-performance API built with Node.js, Fastify, and TypeScript. It exposes a unified, type-safe data interface for every kind of Islamic digital content a modern web, mobile, or desktop application might need: full Quran text, audio recitations, Tafsir, Azkar (supplications), Hadith, prayer times, Hijri/Gregorian date conversion, and Qibla direction.
Every module is engineered around a single core idea: resilience through fallback. If a primary upstream source goes down, the API transparently retries against the next configured provider, returning a consistent shape to the client. Frequently-fetched data is memoized in-process to keep latency low and reduce load on third-party services.
- Multi-source fallback — every endpoint has 2+ upstream providers; if one fails (timeout, 5xx, malformed response, empty result), the next is tried automatically.
- In-process caching — results are memoized with per-endpoint TTLs and concurrent calls are coalesced into a single upstream request.
- Request timeouts — every upstream call is wrapped in
AbortControllerso a slow source can't hang your server. - Rate limiting — built-in per-IP rate limit (configurable via
RATE_LIMIT_MAX/RATE_LIMIT_WINDOW). - Production probes —
/health,/ready, and/metricsfor uptime checks and monitoring. - Type-safe — written in strict TypeScript with
noUncheckedIndexedAccessenabled. - Modular architecture — each domain (
ayat,surah,reciters,azkar,tafsir,hadith,prayer,hijri,qibla) lives in its ownroute.ts/controller.ts/service.tstriplet. - Container-ready — multi-stage
DOCKERFILEproduces a minimalnode:20-alpineruntime image. - CI/CD enforced — pull requests must pass ESLint,
tsc, and Vitest before merge.
The root GET / returns a JSON catalogue of every registered route. GET /health returns liveness info, GET /ready returns readiness and cache stats, and GET /metrics exposes Prometheus text metrics.
| Method | Path | Description |
|---|---|---|
| GET | /surah |
Full list of all 114 surahs |
| GET | /surah/:id |
A single surah by id (1–114) |
| GET | /surah/search?name=الفاتحة |
Search surah by Arabic name |
Fallback sources: mp3quran.net → alquran.cloud → quran.com
| Method | Path | Description |
|---|---|---|
| GET | /ayat |
The full Quran text (cached for 24h) |
| GET | /ayat/:id |
A single aya by absolute number (1–6236) |
| GET | /ayat/:surah/aya/:id |
A single aya by surah + verse-in-surah |
| GET | /ayat/search?text=الله&limit=50 |
Search ayat by text (Arabic-normalized, ignores diacritics) |
Fallback sources: alquran.cloud (Uthmani) → cdn.jsdelivr.net/gh/fawazahmed0/quran-api
| Method | Path | Description |
|---|---|---|
| GET | /reciters |
All reciters with their available moshafs |
| GET | /reciters/:id |
A single reciter |
| GET | /reciters/search?name=... |
Search reciter by Arabic name |
| GET | /reciters/:id/surah/:surah |
Resolve audio URL for a given reciter + surah |
Fallback sources: mp3quran.net → quran.com
| Method | Path | Description |
|---|---|---|
| GET | /tafsir |
List supported editions (muyassar, jalalayn, saadi, waseet, qurtubi) |
| GET | /tafsir/:edition/:surah |
Tafsir for a whole surah |
| GET | /tafsir/:edition/:surah/:aya |
Tafsir for a single aya |
| GET | /tafsir/:edition/:surah?aya=N |
Same, with the aya as a query param |
Fallback sources: alquran.cloud → quranenc.com
| Method | Path | Description |
|---|---|---|
| GET | /azkar |
All available categories (morning, evening, after prayer, …) |
| GET | /azkar/:category |
Items inside a category |
| GET | /azkar/random |
A random zekr |
| GET | /azkar/search?text=...&limit=50 |
Search across all azkar |
Fallback sources: nawafalqari/azkar-api (GitHub) → hisnmuslim.com
| Method | Path | Description |
|---|---|---|
| GET | /hadith |
List of available hadith books (Bukhari, Muslim, Abu-Dawud, …) |
| GET | /hadith/:book?from=1&to=30 |
Hadith range from a book (max 300 per request) |
| GET | /hadith/:book/:number |
A single hadith by its number |
| GET | /hadith/random?book=bukhari |
A random hadith (optionally scoped to a book) |
Fallback sources: api.hadith.gading.dev → cdn.jsdelivr.net/gh/sutanlab/hadith-api
| Method | Path | Description |
|---|---|---|
| GET | /prayer/times?latitude=21.4225&longitude=39.8262 |
Today's timings for coordinates |
| GET | /prayer/times?city=Mecca&country=SA |
Today's timings by city/country |
| GET | /prayer/times?date=06-05-2026&latitude=...&longitude=...&method=4 |
Custom date and calculation method |
Fallback sources: api.aladhan.com/timings → api.aladhan.com/timingsByCity → api.pray.zone (same-day coordinate requests only)
| Method | Path | Description |
|---|---|---|
| GET | /hijri/today |
Today's date in both calendars |
| GET | /hijri/from-gregorian?date=06-05-2026 |
Convert a gregorian date to hijri |
| GET | /hijri/to-gregorian?date=18-11-1447 |
Convert a hijri date to gregorian |
Fallback sources: api.aladhan.com/gToH ↔ api.aladhan.com/hToG
| Method | Path | Description |
|---|---|---|
| GET | /qibla?latitude=24.7136&longitude=46.6753 |
Compass bearing (in degrees) toward the Kaaba |
Fallback sources: api.aladhan.com/qibla → local great-circle computation (always succeeds)
- Runtime: Node.js (v20+ recommended)
- Language: TypeScript (strict,
NodeNextmodules) - Framework: Fastify 5
- Plugins:
@fastify/cors,@fastify/rate-limit - Tooling: ESLint 10, Prettier, Vitest, tsx, dotenv
- Package Manager: pnpm
git clone https://github.com/BonyanOSS/Bonyan-API.git
cd Bonyan-API
pnpm install
cp .env.example .env # adjust PORT / RATE_LIMIT_* if needed
pnpm dev # starts Fastify with hot-reload via tsx watchThe server prints all registered routes on startup. Open http://localhost:3000/ for the live route catalogue.
pnpm lint:check # validates eslint + prettier
pnpm lint # applies eslint + prettier fixes
pnpm build # tsc → dist/
pnpm start # node dist/server.js| Variable | Default | Purpose |
|---|---|---|
PORT |
3000 |
HTTP listen port |
HOST |
0.0.0.0 |
Bind address |
NODE_ENV |
production |
Runtime environment |
RATE_LIMIT_MAX |
120 |
Max requests per window per IP |
RATE_LIMIT_WINDOW |
1 minute |
Rate-limit time window (parsed by @fastify/rate-limit) |
CORS_ORIGIN |
* |
Allowed origins. Use comma-separated origins in production |
TRUST_PROXY |
false |
Trust proxy headers for correct client IPs behind a proxy |
LOG_LEVEL |
info |
Fastify logger level |
CACHE_MAX_ENTRIES |
1000 |
Maximum in-process cache entries |
docker build -t bonyan-api .
docker run -p 3000:3000 --env-file .env bonyan-apipnpm test # full vitest run (69 tests)
pnpm test:watch # interactive watch mode
pnpm test:coverage # generates coverage/lcov.infoTests exercise:
- The shared
runWithFallbackandmemoizeutilities (mocked). - Each module's controller — input validation, error shapes, status codes.
- Live integration smoke tests that tolerate
200,404, or503so the suite stays green even when an upstream is rate-limited or temporarily unreachable.
src/
server.ts # Fastify bootstrap, plugins, route registration
modules/
ayat/ # full Quran text + search
surah/ # surah index
reciters/ # reciter directory + audio resolver
azkar/ # supplications (categories, random, search)
tafsir/ # multi-edition tafsir
hadith/ # 9-books hadith index + lookup
prayer/ # daily prayer timings
hijri/ # hijri ↔ gregorian conversion
qibla/ # qibla direction (with offline fallback)
utils/
fallback.ts # runWithFallback + fetchWithTimeout
cache.ts # in-memory memoize with TTL + concurrent-call coalescing
arabic.ts # Arabic-text normalization for search
http.ts # standard ok / fail / unavailable responders
types/
Api.ts # upstream payload shapes
Items.ts # canonical client-facing shapes
tests/ # vitest specs
.github/workflows/ # CI pipelines (lint, build, test, coverage)
DOCKERFILE # multi-stage production image
We welcome contributions! Direct pushes to main are blocked — every change must go through a Pull Request, and CI must pass (ESLint + tsc + Vitest with coverage upload). See CONTRIBUTING.md, SECURITY.md, SUPPORT.md, SOURCES.md, and ROADMAP.md.
- Fork the repository and clone your fork.
- Create a feature branch:
git checkout -b feature/your-feature. - Lint your code:
pnpm lint. - Test your code:
pnpm test. - Commit using conventional messages:
git commit -m 'feat(azkar): add evening category alias'. - Push and open a PR against
main.
When you add a new upstream source, please:
- Wrap it with
fetchWithTimeoutso it can't hang the server. - Map its payload to the canonical type in
src/types/Items.ts. - Add it as a fallback inside the existing service rather than creating a parallel pipeline.
This software is released under the MIT License.
Bonyan-API هي واجهة برمجة تطبيقات إسلامية متكاملة وعالية الأداء، مبنية على Node.js و Fastify و TypeScript. توفّر واجهة بيانات موحّدة وآمنة النوع لكل ما يحتاجه التطبيق الإسلامي الحديث من محتوى رقمي: نص القرآن الكريم كاملاً، التلاوات الصوتية، التفسير، الأذكار، الأحاديث، مواقيت الصلاة، التحويل بين التاريخ الهجري والميلادي، واتجاه القبلة.
كل وحدة في المشروع مبنية حول فكرة جوهرية واحدة: المرونة من خلال البدائل (Fallback). عند تعطّل المصدر الأساسي، يتنقّل النظام تلقائياً إلى المصدر التالي ضمن قائمة موثّقة من المزوّدين، ويُرجع للعميل نفس الشكل الموحّد دائماً. كما تُخزَّن النتائج المتكررة في الذاكرة لتقليل زمن الاستجابة وتخفيف الضغط على المصادر الخارجية.
- بدائل متعددة لكل نقطة نهاية — كل endpoint مدعوم بأكثر من مزوّد، وفي حال فشل أحدها (timeout / 5xx / استجابة فارغة) يُحاوَل التالي تلقائياً.
- Cache داخلي — كل بيانات يتم جلبها تُحفظ في الذاكرة مع TTL مخصّص، والطلبات المتزامنة تُدمَج في طلب واحد.
- مهلة لكل طلب خارجي — يُلفّ كل fetch بـ
AbortControllerلمنع تعليق الخادم بسبب مصدر بطيء. - تحديد معدّل الطلبات (Rate Limit) — مدمج عبر
@fastify/rate-limit(قابل للتعديل عبر متغيرات البيئة). - آمن النوع (Type-Safe) — مكتوب بالكامل في TypeScript مع
strictوnoUncheckedIndexedAccess. - بنية تركيبية — كل وحدة في مجلدها الخاص (
route.ts/controller.ts/service.ts). - جاهز للحاويات —
DOCKERFILEمتعدد المراحل ينتج صورةnode:20-alpineخفيفة. - CI/CD صارم — كل PR يجب أن يجتاز ESLint وبناء TypeScript واختبارات Vitest.
GET / يُرجع قائمة بكل المسارات المسجّلة. GET /health يُرجع حالة الخادم.
| Method | Path | الوصف |
|---|---|---|
| GET | /surah |
كل السور الـ 114 |
| GET | /surah/:id |
سورة محددة (1–114) |
| GET | /surah/search?name=الفاتحة |
بحث بالاسم العربي |
البدائل: mp3quran.net → alquran.cloud → quran.com
| Method | Path | الوصف |
|---|---|---|
| GET | /ayat |
كل القرآن (مُخزَّن لمدة 24 ساعة) |
| GET | /ayat/:id |
آية برقمها المطلق (1–6236) |
| GET | /ayat/:surah/aya/:id |
آية برقم السورة + ترتيبها داخلها |
| GET | /ayat/search?text=الله&limit=50 |
بحث في النص (يتجاهل التشكيل والاختلافات الإملائية) |
البدائل: alquran.cloud (المصحف العثماني) → cdn.jsdelivr.net/gh/fawazahmed0/quran-api
| Method | Path | الوصف |
|---|---|---|
| GET | /reciters |
كل القرّاء مع المصاحف المتاحة |
| GET | /reciters/:id |
قارئ محدد |
| GET | /reciters/search?name=... |
بحث القارئ بالاسم |
| GET | /reciters/:id/surah/:surah |
رابط الصوت لقارئ + سورة |
البدائل: mp3quran.net → quran.com
| Method | Path | الوصف |
|---|---|---|
| GET | /tafsir |
الإصدارات المدعومة (muyassar, jalalayn, saadi, waseet, qurtubi) |
| GET | /tafsir/:edition/:surah |
تفسير سورة كاملة |
| GET | /tafsir/:edition/:surah/:aya |
تفسير آية واحدة |
البدائل: alquran.cloud → quranenc.com
| Method | Path | الوصف |
|---|---|---|
| GET | /azkar |
كل التصنيفات (الصباح، المساء، أذكار بعد الصلاة، …) |
| GET | /azkar/:category |
عناصر تصنيف معين |
| GET | /azkar/random |
ذكر عشوائي |
| GET | /azkar/search?text=... |
بحث في كل الأذكار |
البدائل: nawafalqari/azkar-api (GitHub) → hisnmuslim.com
| Method | Path | الوصف |
|---|---|---|
| GET | /hadith |
الكتب المتاحة (البخاري، مسلم، أبو داود، …) |
| GET | /hadith/:book?from=1&to=30 |
جلب نطاق من الأحاديث |
| GET | /hadith/:book/:number |
حديث محدد برقمه |
| GET | /hadith/random?book=bukhari |
حديث عشوائي |
البدائل: api.hadith.gading.dev → cdn.jsdelivr.net/gh/sutanlab/hadith-api
| Method | Path | الوصف |
|---|---|---|
| GET | /prayer/times?latitude=21.4225&longitude=39.8262 |
مواقيت اليوم بالإحداثيات |
| GET | /prayer/times?city=Mecca&country=SA |
مواقيت اليوم بالمدينة والدولة |
| GET | /prayer/times?date=06-05-2026&...&method=4 |
تاريخ مخصص + طريقة حساب |
البدائل: api.aladhan.com/timings → timingsByCity → api.pray.zone
| Method | Path | الوصف |
|---|---|---|
| GET | /hijri/today |
تاريخ اليوم بالتقويمين |
| GET | /hijri/from-gregorian?date=06-05-2026 |
ميلادي → هجري |
| GET | /hijri/to-gregorian?date=18-11-1447 |
هجري → ميلادي |
البدائل: api.aladhan.com/gToH ↔ api.aladhan.com/hToG
| Method | Path | الوصف |
|---|---|---|
| GET | /qibla?latitude=24.7136&longitude=46.6753 |
اتجاه القبلة بالدرجات |
البدائل: api.aladhan.com/qibla → حساب محلي بصيغة الدائرة العظمى (لا يفشل أبداً)
- بيئة التشغيل: Node.js (يُنصح بالإصدار 20 فما فوق)
- اللغة: TypeScript
- إطار العمل: Fastify 5
- الإضافات:
@fastify/cors،@fastify/rate-limit - الأدوات: ESLint 10، Prettier، Vitest، tsx، dotenv
- مدير الحزم: pnpm
git clone https://github.com/BonyanOSS/Bonyan-API.git
cd Bonyan-API
pnpm install
cp .env.example .env
pnpm devpnpm lint:check
pnpm lint
pnpm build
pnpm start| المتغير | القيمة الافتراضية | الوصف |
|---|---|---|
PORT |
3000 |
منفذ HTTP |
HOST |
0.0.0.0 |
عنوان الربط |
NODE_ENV |
production |
بيئة التشغيل |
RATE_LIMIT_MAX |
120 |
الحد الأقصى للطلبات لكل IP |
RATE_LIMIT_WINDOW |
1 minute |
نافذة تحديد المعدّل |
CORS_ORIGIN |
* |
النطاقات المسموح لها |
TRUST_PROXY |
false |
الثقة بترويسات البروكسي |
LOG_LEVEL |
info |
مستوى سجلات Fastify |
CACHE_MAX_ENTRIES |
1000 |
حد عناصر الكاش الداخلي |
docker build -t bonyan-api .
docker run -p 3000:3000 --env-file .env bonyan-apipnpm test # 69 اختبار
pnpm test:watch # وضع المراقبة
pnpm test:coverage # مع تقرير التغطيةنُرحّب بأي مساهمة! الدفع المباشر للفرع main ممنوع — يجب أن تمر كل مساهمة عبر Pull Request، وأن تجتاز خطوط CI.
- اعمل Fork للمستودع وانسخه محلياً.
- أنشئ فرعاً للميزة الجديدة:
git checkout -b feature/your-feature. - شغّل ESLint:
pnpm lint. - شغّل الاختبارات:
pnpm test. - أنشئ commit بصيغة Conventional:
git commit -m 'feat(azkar): إضافة تصنيف جديد'. - ادفع التغييرات وافتح PR على فرع
main.
عند إضافة مصدر جديد:
- استخدم
fetchWithTimeoutحتى لا يُعلِّق المصدر البطيء الخادم. - حوّل بيانات المصدر إلى الشكل الموحّد في
src/types/Items.ts. - أضفه كـ fallback ضمن الـ service الموجود بدلاً من إنشاء مسار مستقل.
هذا المشروع مُرخَّص بموجب رخصة MIT.