dorar_hadith 0.1.1
dorar_hadith: ^0.1.1 copied to clipboard
A comprehensive Dart library for accessing Dorar.net hadith database. Search hadiths, get explanations (sharh), browse scholars, books, and narrators. Includes offline reference data for 688 books, 20 [...]
بسم الله الرحمن الرحيم #
Dorar Hadith #
تغيير اللغة: 🇸🇦 AR #
A Dart library to search and retrieve hadith and related data from Dorar Al-Sanniyah.
Inspired by and partially based on the repository dorar-hadith-api by Ahmed Al-Tabarani. Works with any Dart program without requiring Flutter.
Terminology #
- In this README, the word "scholar" always means a hadith scholar (mohdith). We keep the term "mohdith" in code and types to match the API and models.
Library Highlights #
- Fast hadith search with filters by narrator, book, grade, hadith scholar (mohdith), and more
- Retrieve detailed hadith information
- Search and fetch hadith explanations (Sharh)
- Find similar hadiths and alternate sahih versions
- Offline browsing for books, narrators, and hadith scholars (mohdith) used for filtering
Search Capabilities #
- Search by hadith text
- Filter by hadith grade
- Filter by hadith scholars (mohdith)
- Filter by narrators
- Filter by books
- Filter by hadith type (Qudsi, Athar, etc.)
- Pagination metadata
Installation #
Run:
dart pub add dorar_hadith
Or using Flutter:
flutter pub add dorar_hadith
Quick Start #
import 'package:dorar_hadith/dorar_hadith.dart';
void main() async {
// Create the client
final client = DorarClient();
try {
// Search for hadiths about prayer
final results = await client.searchHadith(
HadithSearchParams(value: 'الصلاة', page: 1),
);
print('Found ${results.data.length} hadiths');
// Print first hadith
if (results.data.isNotEmpty) {
final hadith = results.data.first;
print('Hadith: ${hadith.hadith}');
print('Narrator: ${hadith.rawi}');
print('Scholar: ${hadith.mohdith}');
print('Grade: ${hadith.grade}');
}
} on DorarException catch (e) {
print('Error: ${getExceptionMessage(e)}');
} finally {
// Clean up resources (important: closes database connections)
await client.dispose();
}
}
For a complete example covering all library features, see:
example/example.dart
Usage #
Important Note #
Most operations in DorarClient and the other services return results inside an ApiResponse object to simplify pagination.
ApiResponse has two members:
- The result:
data - Pagination metadata:
SearchMetadata
This makes it easier to request the next page when needed.
Quick Hadith Search #
Using client.searchHadith is fast, but the hadith info is partial and without identifiers (hadithId, bookId, etc).
- Results are limited to ~15 hadiths, and filters can be used.
- Each result includes:
- Text:
Hadith.hadith - Narrator:
Hadith.rawi - Scholar:
Hadith.mohdith - Book:
Hadith.book - Number or page in the book:
Hadith.numberOrPage - Grade:
Hadith.grade
- Text:
final results = await client.searchHadith(
HadithSearchParams(value: 'الإيمان'),
);
for (var hadith in results.data) {
print('${hadith.hadith}');
print('Grade: ${hadith.grade}');
}
Detailed Search with Filters #
Note: Due to how Dorar works, in detailed search the verdict appears in explainGrade, not grade.
final params = HadithSearchParams(
value: 'الصيام',
page: 1,
degrees: [HadithDegree.authenticHadith], // Only sahih
mohdith: [MohdithReference.bukhari],
searchMethod: SearchMethod.anyWord,
zone: SearchZone.qudsi,
);
final results = await client.searchHadithDetailed(params);
Get Hadith by ID #
final hadith = await client.getHadithById('12345');
print('Hadith: ${hadith.hadith}');
print('Book: ${hadith.book}');
print('Grade: ${hadith.grade}');
Similar, Usul (Sources), Alternate Sahih #
Note: The Hadith model has flags to check availability:
hasAlternateHadithSahihfor alternate sahihhasSimilarHadithfor similar hadithshasUsulHadithfor sources
// Get similar
final similar = await client.hadith.getSimilar('12345');
// Get alternate sahih
final alternate = await client.hadith.getAlternate('12345');
// Get sources
final usul = await client.hadith.getUsul('12345');
print('Main hadith: ${usul.hadith.hadith}');
print('Sources: ${usul.count}');
Search for Sharh (Explanation) #
Note: When using client.searchHadithDetailed, if a hadith has a sharh, you will find its ID in sharhMetadata. Use it as follows:
// Get sharh by ID
final sharh = await client.sharh.getById('789');
// Search by sharh text
final sharhByText = await client.sharh.getByText('إنما الأعمال بالنيات');
Reference Data (Offline) #
Reference data is used for filtering (hadith scholar [mohdith], book, narrator) and is available offline for speed and usability.
Note: Reference items contain only id and name (e.g., Sahih al-Bukhari). For full details, fetch via the API. See: “Get Book/Scholar Details”.
Search Scholars (Hadith scholars – mohdith)
// By name
final bukhari = await client.mohdithRef.searchMohdith('البخاري');
// By ID
final scholar = await client.mohdithRef.getMohdithById('256');
// List paginated
final allScholars = await client.mohdithRef.getAllMohdith(limit: 50);
// Multiple by IDs
final scholars = await client.mohdithRef.getMohdithByIds(['256', '179']);
// Shortcut
final results = await client.searchMohdith('أحمد');
Search Books
// By name
final sahihBooks = await client.bookRef.searchBook('صحيح');
// By ID
final book = await client.bookRef.getBookById('6216');
// List paginated
final allBooks = await client.bookRef.getAllBooks(limit: 100, offset: 0);
// Shortcut
final results = await client.searchBooks('سنن');
Search Narrators
// By name
final narrators = await client.rawiRef.searchRawi('أبو هريرة', limit: 10);
// By ID
final abuHurayrah = await client.rawiRef.getRawiById(4396);
// Paginated listing
final page1 = await client.rawiRef.getAllRawi(limit: 50, offset: 0);
// Counts
final total = await client.rawiRef.countRawi();
final searchCount = await client.rawiRef.countRawi(query: 'عبد الله');
// Shortcut
final results = await client.searchRawi('عمر');
// Important: dispose after use to avoid warnings
await client.dispose();
Predefined Constants
To make filtering easier without repeatedly searching, popular scholars, books, and narrators are provided as ready-to-use constants. If you’d like to add more, please open an issue on GitHub.
// Sample scholar constants
MohdithReference.bukhari
MohdithReference.muslim
MohdithReference.abuDawud
// ... 17 total
// Sample book constants
BookReference.sahihBukhari
BookReference.sahihMuslim
// ... 20 total
// Sample narrator constants
RawiReference.abuHurayrah
RawiReference.aisha
// ... 21 total
// Using constants in filters
final params = HadithSearchParams(
value: 'الصلاة',
page: 1,
mohdith: [MohdithReference.Bukhari],
books: [BookReference.sahihBukhari],
);
final results = await client.hadith.searchViaSite(params);
Get Book or Hadith Scholar (Mohdith) Details #
// Book details from API
final book = await client.book.getById('123');
print('Book: ${book.name}');
print('Author: ${book.author}');
// Hadith scholar (mohdith) details from API
final scholar = await client.mohdith.getById('456');
print('Name: ${scholar.name}');
print('Bio: ${scholar.info}');
Available Options #
This section describes all models and options provided by the library.
Hadith Model #
Represents a hadith with all its related information.
class Hadith {
// Basic hadith info
final String hadith; // Hadith text
final String? hadithId; // Unique hadith ID
// Chain and scholars
final String rawi; // Narrator name
final String mohdith; // Scholar name
final String? mohdithId; // Scholar ID
// Source info
final String book; // Source book name
final String? bookId; // Book ID
final String numberOrPage; // Page number or hadith number in the book
// Grading and takhrij
final String grade; // Hadith grade (Sahih, Da'if, etc.)
final String? explainGrade; // Grade explanation
final String? takhrij; // Takhrij information
// Relations and links
final bool hasSimilarHadith; // Has similar hadiths?
final bool hasAlternateHadithSahih; // Has alternate sahih?
final bool hasUsulHadith; // Has sources?
// Dorar links
final String? similarHadithDorar; // Similar hadiths link
final String? alternateHadithSahihDorar; // Alternate sahih link
final String? usulHadithDorar; // Sources link
// Sharh info
final bool hasSharhMetadata; // Has sharh available?
final SharhMetadata? sharhMetadata; // Sharh metadata (if any)
}
Important:
- Use
hasSimilarHadithto check before callingclient.hadith.getSimilar() - Use
hasAlternateHadithSahihbeforeclient.hadith.getAlternate() - Use
hasUsulHadithbeforeclient.hadith.getUsul() - Use
hasSharhMetadata; if true, you’ll findsharhMetadata.id
Sharh Model #
Represents a hadith with its explanation.
class Sharh {
// Base hadith info
final String hadith; // Hadith text
final String rawi; // Narrator
final String mohdith; // Scholar
final String book; // Source book
final String numberOrPage; // Page/hadith number
final String grade; // Grade
final String? takhrij; // Takhrij
// Sharh info
final bool hasSharhMetadata; // Has sharh?
final SharhMetadata? sharhMetadata; // Sharh metadata
// Helper to access sharh text directly
String? get sharhText => sharhMetadata?.sharh;
}
Usage:
final sharh = await client.sharh.getById('789');
if (sharh.hasSharhMetadata && sharh.sharhText != null) {
print('Sharh: ${sharh.sharhText}');
}
SharhMetadata #
class SharhMetadata {
final String id; // Sharh ID
final bool isContainSharh; // Whether sharh text is included
final String? sharh; // Sharh text (if any)
}
UsulHadith (Sources) #
Represents a hadith with all its sources.
class UsulHadith {
final Hadith hadith; // Base hadith
final List<UsulSource> sources; // All sources
final int count; // Sources count
}
// Single source entry
class UsulSource {
final String source; // Source name and page
final String chain; // Chain of narration
final String hadithText; // Hadith text in this source
}
Example:
final usulResponse = await client.hadith.getUsul('12345');
final usul = usulResponse.data;
print('Sources: ${usul.count}');
for (var source in usul.sources) {
print('Source: ${source.source}');
print('Chain: ${source.chain}');
}
BookInfo #
Full book details (via API).
class BookInfo {
final String name; // Book name
final String bookId; // Unique ID
final String author; // Author
final String reviewer; // Reviewer
final String publisher; // Publisher
final String edition; // Edition
final String editionYear; // Year of edition
}
Usage:
final book = await client.book.getById('6216');
print('${book.name} - ${book.author}');
print('Publisher: ${book.publisher}');
MohdithInfo #
Full hadith scholar (mohdith) details (via API).
class MohdithInfo {
final String name; // Scholar name
final String mohdithId; // Unique ID
final String info; // Biography and details
}
Usage:
final mohdith = await client.mohdith.getById('256');
print('Name: ${mohdith.name}');
print('Bio: ${mohdith.info}');
Reference Items #
Lightweight items for offline filtering. All extend ReferenceItem.
BookItem
class BookItem extends ReferenceItem {
final String id; // Book ID
final String name; // Book name
final String? author; // Author (if any)
final String? mohdithId; // Hadith scholar (mohdith) author ID
final String? category; // Category (if any)
}
Usage:
// Offline search in books
final books = await client.bookRef.searchBook('صحيح', limit: 10);
for (var book in books) {
print('${book.name} - ${book.author}');
// Get full details (online)
final fullInfo = await client.book.getById(book.id);
}
MohdithItem
class MohdithItem extends ReferenceItem {
final String id; // Scholar ID
final String name; // Scholar name
final int? deathYear; // Death year (Hijri)
final String? era; // Era (if any)
}
Usage:
// Offline search in scholars
final scholars = await client.mohdithRef.searchMohdith('البخاري', limit: 5);
for (var scholar in scholars) {
print('${scholar.name}');
if (scholar.deathYear != null) {
print('Died in: ${scholar.deathYear} AH');
}
}
RawiItem
class RawiItem extends ReferenceItem {
final String id; // Narrator ID
final String name; // Narrator name
}
Usage:
// Offline narrator search
final narrators = await client.rawiRef.searchRawi('أبو هريرة', limit: 3);
for (var narrator in narrators) {
print(narrator.name);
}
// Counts
final total = await client.rawiRef.countRawi();
final searchCount = await client.rawiRef.countRawi(query: 'عبد الله');
ApiResponse #
All search and retrieval operations return results inside ApiResponse to simplify pagination.
class ApiResponse<T> {
final T data; // Actual data (hadith, list, etc.)
final SearchMetadata metadata; // Extra info about the result
}
Examples:
// Search returns ApiResponse<List<Hadith>>
final response = await client.searchHadith(
HadithSearchParams(value: 'الصلاة', page: 1),
);
print('Count: ${response.data.length}');
print('Current page: ${response.metadata.page}');
print('From cache: ${response.metadata.isCached}');
// Usul returns ApiResponse<UsulHadith>
final usulResponse = await client.hadith.getUsul('12345');
print('Sources: ${usulResponse.data.count}');
SearchMetadata #
Additional info about a search result.
class SearchMetadata {
final int length; // Number of returned results
final int? page; // Current page number
final bool? removeHtml; // Whether HTML tags were removed
final bool? specialist; // Include specialist hadiths?
final int? numberOfNonSpecialist; // Non-specialist count
final int? numberOfSpecialist; // Specialist count
final bool isCached; // Result from cache?
final int? usulSourcesCount; // Sources count (for Usul requests)
// Create a modified copy
SearchMetadata copyWith({...});
}
Usage:
final response = await client.searchHadith(params);
final meta = response.metadata;
if (meta.isCached) {
print('Result is from cache - fast!');
}
print('Page ${meta.page} of ???');
print('Results: ${meta.length}');
HadithSearchParams #
All search filters and parameters.
class HadithSearchParams {
// Required
final String value; // Search text
// Optional - search options
final int page; // Page (default: 1)
final bool removeHtml; // Remove HTML (default: true)
final bool specialist; // Include specialist hadiths (default: false)
final String? exclude; // Words/phrases to exclude
// Optional - filters
final SearchMethod? searchMethod; // Search method (all/any/exact)
final SearchZone? zone; // Hadith type (Marfoo/Qudsi/Athar/Sharh)
final List<HadithDegree>? degrees; // Filter by grade
final List<MohdithReference>? mohdith; // Filter by scholars
final List<BookReference>? books; // Filter by books
final List<RawiReference>? rawi; // Filter by narrators
// Create a modified copy
HadithSearchParams copyWith({...});
}
Examples:
// Minimal search
final simple = HadithSearchParams(value: 'الصلاة', page: 1);
// With specific filters
final filtered = HadithSearchParams(
value: 'الإيمان',
page: 1,
degrees: [HadithDegree.authenticHadith], // Sahih only
mohdith: [MohdithReference.bukhari], // Al-Bukhari only
books: [BookReference.sahihBukhari], // Sahih al-Bukhari only
searchMethod: SearchMethod.allWords, // All words
zone: SearchZone.qudsi, // Qudsi hadiths
);
// Advanced with exclusions
final advanced = HadithSearchParams(
value: 'الجنة النار',
page: 1,
exclude: 'الدنيا', // Exclude the word "الدنيا"
degrees: [
HadithDegree.authenticHadith,
HadithDegree.authenticChain,
],
mohdith: [
MohdithReference.bukhari,
MohdithReference.muslim,
],
searchMethod: SearchMethod.anyWord, // Any word
removeHtml: true, // Remove HTML
);
// Modify existing params
final modified = simple.copyWith(
page: 2, // Go to page 2
degrees: [HadithDegree.authenticHadith], // Add filter
);
final results = await client.searchHadithDetailed(advanced);
HadithDegree #
Static values representing hadith grading according to scholars.
enum HadithDegree {
all, // All grades (no filter)
authenticHadith, // Scholars ruled the hadith itself as sahih
authenticChain, // Scholars ruled the chain as sahih
weakHadith, // Scholars ruled the hadith as weak
weakChain, // Scholars ruled the chain as weak
// Each value has:
final String id; // ID used in the API
final String label; // Arabic label
}
Usage:
// Filter sahih only
final params = HadithSearchParams(
value: 'الصدقة',
page: 1,
degrees: [HadithDegree.authenticHadith],
);
// Sahih (hadith or chain)
final params2 = HadithSearchParams(
value: 'الصدقة',
page: 1,
degrees: [
HadithDegree.authenticHadith,
HadithDegree.authenticChain,
],
);
// Helpers
print(HadithDegree.authenticHadith.toString()); // Arabic label
print(HadithDegree.authenticHadith.toQueryParam()); // API id
SearchMethod #
How the text search is performed.
enum SearchMethod {
allWords, // All words (AND)
anyWord, // Any word (OR)
exactMatch, // Exact phrase
// Each value has:
final String id; // API id
final String label; // Arabic label
}
Usage:
// All words (AND)
final allWords = HadithSearchParams(
value: 'الصلاة الزكاة',
page: 1,
searchMethod: SearchMethod.allWords, // Must contain both words
);
// Any word (OR)
final anyWord = HadithSearchParams(
value: 'الصلاة الزكاة',
page: 1,
searchMethod: SearchMethod.anyWord, // Contains either word
);
// Exact phrase
final exact = HadithSearchParams(
value: 'إنما الأعمال بالنيات',
page: 1,
searchMethod: SearchMethod.exactMatch, // Exact phrase
);
// Helpers
print(SearchMethod.allWords.toString()); // "جميع الكلمات"
print(SearchMethod.allWords.toQueryParam()); // "w"
SearchZone #
Filters by hadith type.
enum SearchZone {
all, // All hadiths (no filter)
marfoo, // Marfoo (attributed to the Prophet ﷺ)
qudsi, // Qudsi (from Allah)
sahabaAthar, // Companions' athar
sharh, // Explanations (shuruh)
// Each value has:
final String id; // API id
final String label; // Arabic label
}
Usage:
// Qudsi only
final qudsi = HadithSearchParams(
value: 'الجنة',
page: 1,
zone: SearchZone.qudsi,
);
// Marfoo only
final marfoo = HadithSearchParams(
value: 'الصلاة',
page: 1,
zone: SearchZone.marfoo,
);
// Sahaba athar
final athar = HadithSearchParams(
value: 'عمر بن الخطاب',
page: 1,
zone: SearchZone.sahabaAthar,
);
// Helpers
print(SearchZone.qudsi.toString()); // "الأحاديث القدسية"
print(SearchZone.qudsi.toQueryParam()); // "1"
Client Options #
final client = DorarClient(
timeout: Duration(seconds: 15), // Request timeout (default: 15s)
enableCache: true, // Enable cache (default: true)
cacheTtl: Duration(hours: 24), // Cache TTL (default: 24h)
);
Cache Management #
// Cache stats
final stats = client.getCacheStats();
print('Total entries: ${stats.totalEntries}');
print('Valid entries: ${stats.validEntries}');
print('Hit rate: ${(stats.hitRate * 100).toStringAsFixed(1)}%');
// Clear all cache
client.clearCache();
// Clear per-service cache
client.hadith.clearCache();
client.sharh.clearCache();
client.book.clearCache();
Resource Cleanup #
Always call dispose() when done to close database connections and avoid warnings.
void main() async {
final client = DorarClient();
try {
// Use the library
final results = await client.searchHadith(
HadithSearchParams(value: 'الصلاة', page: 1),
);
} finally {
// Mandatory cleanup
await client.dispose();
}
}
Error Handling #
The library uses a sealed class hierarchy for exceptions, enabling safer handling with pattern matching.
DorarException Types
All errors extend DorarException with the following types:
// 1. Network error - connectivity issues
DorarNetworkException {
final String message;
final String? details;
}
// 2. Timeout - request took too long
DorarTimeoutException {
final String message;
final Duration timeout;
final String? details;
}
// 3. Not found - missing resource
DorarNotFoundException {
final String message;
final String resource;
final String? details;
}
// 4. Validation error - invalid input
DorarValidationException {
final String message;
final String? field; // Field name
final String? rule; // Violated rule
final String? details;
}
// 5. Server error - Dorar server issue
DorarServerException {
final String message;
final int statusCode; // HTTP status code
final String? details;
}
// 6. Parse error - response parsing issue
DorarParseException {
final String message;
final String? expectedType; // Expected type
final String? details;
}
// 7. Rate limit - too many requests
DorarRateLimitException {
final String message;
final int? limit; // Max requests
final DateTime? resetAt; // Reset time
final String? details;
}
Comprehensive Handling with Switch Expression
try {
final results = await client.searchHadith(
HadithSearchParams(value: 'الصلاة', page: 1),
);
} on DorarException catch (e) {
// Pattern matching - compiler ensures coverage!
final message = switch (e) {
DorarNetworkException() =>
'🌐 Network error: ${e.message}\n'
'Please check your internet connection',
DorarTimeoutException() =>
'⏱️ Request timed out after ${e.timeout.inSeconds} seconds\n'
'Try again later',
DorarNotFoundException() =>
'🔍 Not found: ${e.resource}\n'
'Verify the identifier',
DorarValidationException() =>
'✋ Validation error: ${e.message}\n'
'${e.field != null ? "Field: ${e.field}" : ""}',
DorarServerException() =>
'🖥️ Server error (${e.statusCode}): ${e.message}',
DorarParseException() =>
'📄 Parse error: ${e.message}',
DorarRateLimitException() =>
'🚫 Rate limit exceeded\n'
'${e.resetAt != null ? "Retry after: ${e.resetAt}" : ""}',
};
print(message);
}
Helper Function for Error Messages
import 'package:dorar_hadith/dorar_hadith.dart';
try {
final results = await client.searchHadith(params);
} on DorarException catch (e) {
// Use the helper
print(getExceptionMessage(e));
}
Available Services #
DorarClient exposes multiple focused services, each responsible for specific functionality.
Hadith Service #
The core service for searching and fetching hadiths.
final client = DorarClient();
// 1. Quick search (API - ~15 results)
final quickResults = await client.searchHadith(
HadithSearchParams(value: 'الصلاة', page: 1),
);
// 2. Detailed search (Site - ~30 results)
final detailedResults = await client.searchHadithDetailed(
HadithSearchParams(value: 'الصلاة', page: 1),
);
// 3. Get by ID
final hadith = await client.getHadithById('12345');
// Or use the service directly
final sameResults = await client.hadith.searchViaApi(params);
final sameDetailed = await client.hadith.searchViaSite(params);
final sameHadith = await client.hadith.getById('12345');
// 4. Similar hadiths
if (hadith.hasSimilarHadith && hadith.hadithId != null) {
final similar = await client.hadith.getSimilar(hadith.hadithId!);
print('Found ${similar.length} similar hadiths');
}
// 5. Alternate sahih
if (hadith.hasAlternateHadithSahih && hadith.hadithId != null) {
final alternate = await client.hadith.getAlternate(hadith.hadithId!);
if (alternate != null) {
print('Alternate sahih: ${alternate.hadith}');
}
}
// 6. Usul (sources)
if (hadith.hasUsulHadith && hadith.hadithId != null) {
final usulResponse = await client.hadith.getUsul(hadith.hadithId!);
final usul = usulResponse.data;
print('Sources: ${usul.count}');
for (var source in usul.sources) {
print('- ${source.source}: ${source.chain}');
}
}
// 7. Clear cache
client.hadith.clearCache();
Sharh Service #
Search and retrieve hadith explanations.
// 1. Search by hadith text
final sharh = await client.sharh.getByText('إنما الأعمال بالنيات');
// You can also search in specialist hadiths
final specialistSharh = await client.sharh.getByText(
'نص الحديث',
specialist: true,
);
// 2. Get by ID
// (ID comes from hadith.sharhMetadata.id)
final hadith = await client.getHadithById('12345');
if (hadith.hasSharhMetadata && hadith.sharhMetadata != null) {
final sharhId = hadith.sharhMetadata!.id;
final sharh = await client.sharh.getById(sharhId);
if (sharh.sharhText != null) {
print('Sharh: ${sharh.sharhText}');
}
}
// 3. Clear cache
client.sharh.clearCache();
Book Service (Detailed) #
Fetch detailed book info (requires internet).
// Get book by ID
final book = await client.book.getById('6216'); // Sahih al-Bukhari
print('Book: ${book.name}');
print('Author: ${book.author}');
print('Reviewer: ${book.reviewer}');
print('Publisher: ${book.publisher}');
print('Edition: ${book.edition}');
print('Edition Year: ${book.editionYear}');
// Clear cache
client.book.clearCache();
Mohdith Service (Detailed) #
Fetch detailed scholar info (requires internet).
// Get scholar by ID
final mohdith = await client.mohdith.getById('256'); // Imam al-Bukhari
print('Name: ${mohdith.name}');
print('Bio: ${mohdith.info}');
// Clear cache
client.mohdith.clearCache();
Book Reference Service (Offline) #
Search available books without internet.
// 1. Search by name
final books = await client.bookRef.searchBook('صحيح', limit: 10);
// Or shortcut
final sameBooks = await client.searchBooks('صحيح');
for (var book in books) {
print('${book.name} - ${book.author}');
}
// 2. Get by ID
final bukhari = await client.bookRef.getBookById('6216');
print(bukhari.name); // صحيح البخاري
// 3. Get multiple by IDs
final multipleBooks = await client.bookRef.getBooksByIds([
'6216', // Sahih al-Bukhari
'3662', // Sahih Muslim
]);
// 4. List all with pagination
final allBooks = await client.bookRef.getAllBookss(
limit: 50,
offset: 0,
);
// 5. Counts
final totalBooks = await client.bookRef.countBooks();
final sahihBooks = await client.bookRef.countBooks(query: 'صحيح');
print('Total books: $totalBooks');
print('"Sahih" books: $sahihBooks');
Mohdith Reference Service (Offline) #
Search available scholars without internet.
// 1. Search by name
final scholars = await client.mohdithRef.searchMohdith('البخاري', limit: 5);
// Or shortcut
final sameScholars = await client.searchMohdith('البخاري');
for (var scholar in scholars) {
print('${scholar.name}');
if (scholar.deathYear != null) {
print('Death year: ${scholar.deathYear} AH');
}
}
// 2. Get by ID
final bukhari = await client.mohdithRef.getMohdithById('256');
print(bukhari.name); // البخاري
// 3. Get multiple by IDs
final multipleScholars = await client.mohdithRef.getMohdithByIds([
'256', // al-Bukhari
'261', // Muslim
]);
// 4. List all with pagination
final allScholars = await client.mohdithRef.getAllMohdith(
limit: 50,
offset: 0,
);
// 5. Counts
final totalScholars = await client.mohdithRef.countMohdith();
final classicalScholars = await client.mohdithRef.countMohdith(
query: 'أحمد',
);
print('Total scholars: $totalScholars');
Rawi Reference Service (Offline) #
Search available narrators without internet.
// 1. Search by name
final narrators = await client.rawiRef.searchRawi('أبو هريرة', limit: 10);
// Or shortcut
final sameNarrators = await client.searchRawi('أبو هريرة');
for (var narrator in narrators) {
print(narrator.name);
}
// 2. Get by ID
final abuHurayrah = await client.rawiRef.getRawiById(4396);
print(abuHurayrah.name); // أبو هريرة عبد الرحمن بن صخر الدوسي
// 3. Get multiple by IDs
final multipleNarrators = await client.rawiRef.getRawiByIds([
4396, // Abu Hurayrah
5593, // Aishah
]);
// 4. List all with pagination
final allNarrators = await client.rawiRef.getAllRawi(
limit: 100,
offset: 0,
);
// 5. Counts
final totalNarrators = await client.rawiRef.countRawi();
final abdullahNarrators = await client.rawiRef.countRawi(query: 'عبد الله');
print('Total narrators: $totalNarrators');
print('"Abdullah" narrators: $abdullahNarrators');
Predefined Filter Constants #
The library provides predefined constants for common scholars, books, and narrators to simplify filtering.
MohdithReference (Scholars)
// 20 scholars
MohdithReference.all // All (no filter) - ID: 0
MohdithReference.malik // Imam Malik - ID: 179
MohdithReference.shafii // Imam al-Shafi'i - ID: 204
MohdithReference.ahmad // Imam Ahmad - ID: 241
MohdithReference.bukhari // al-Bukhari - ID: 256
MohdithReference.muslim // Muslim - ID: 261
MohdithReference.ibnMajah // Ibn Majah - ID: 273
MohdithReference.abuDawud // Abu Dawud - ID: 275
MohdithReference.tirmidhi // al-Tirmidhi - ID: 279
MohdithReference.nasai // al-Nasa'i - ID: 303
MohdithReference.sufyanThawri // Sufyan al-Thawri - ID: 161
MohdithReference.ibnMubarak // Abdullah b. al-Mubarak - ID: 181
MohdithReference.sufyanIbnUyaynah // Sufyan b. 'Uyaynah - ID: 198
MohdithReference.ishaqIbnRahawayh // Ishaq b. Rahawayh - ID: 238
MohdithReference.darimi // al-Darimi - ID: 250
MohdithReference.ibnKhuzaymah // Ibn Khuzaymah - ID: 311
MohdithReference.ibnHibban // Ibn Hibban - ID: 354
MohdithReference.hakim // al-Hakim - ID: 405
MohdithReference.bayhaqi // al-Bayhaqi - ID: 458
MohdithReference.tabarani // al-Tabarani - ID: 360
// Each value has id and name
final bukhari = MohdithReference.bukhari;
print(bukhari.id); // "256"
print(bukhari.name); // "البخاري"
// Use in filters
final params = HadithSearchParams(
value: 'الصلاة',
page: 1,
mohdith: [MohdithReference.bukhari],
);
// Get numeric id if needed
final bukhariId = int.parse(MohdithReference.bukhari.id);
BookReference (Books)
// 21 books
BookReference.all // All (no filter)
BookReference.sahihBukhari // Sahih al-Bukhari (6216)
BookReference.sahihMuslim // Sahih Muslim (3088)
BookReference.arbainNawawi // Al-Arba'in al-Nawawiyyah (13457)
BookReference.sahihMusnad // Al-Sahih al-Musnad (96)
BookReference.sunanAbuDawud // Sunan Abi Dawud (4549)
BookReference.jamiTirmidhi // Jami' al-Tirmidhi (3662)
BookReference.sunanNasai // Sunan al-Nasa'i (5766)
BookReference.sunanIbnMajah // Sunan Ibn Majah (5299)
BookReference.musnadAhmad // Musnad Ahmad (14)
BookReference.muwattaMalik // Muwatta' Malik (6453)
BookReference.musnadDarimi // Sunan al-Darimi (6277)
BookReference.sahihIbnKhuzaymah // Sahih Ibn Khuzaymah (3024)
BookReference.sahihIbnHibban // Sahih Ibn Hibban (5876)
BookReference.mustadrakHakim // Al-Mustadrak (2800)
BookReference.sunanBayhaqiKubra // Al-Sunan al-Kubra (7989)
BookReference.sunanDaraqutni // Sunan al-Daraqutni (3233)
BookReference.musannafIbnAbiShaybah // Musannaf Ibn Abi Shaybah (6598)
BookReference.musannafAbdRazzaq // Musannaf 'Abd al-Razzaq (7613)
BookReference.riyadSalihin // Riyad al-Salihin (10106)
BookReference.bulughMaram // Bulugh al-Maram (9927)
// Each value has id and name
final bukhari = BookReference.sahihBukhari;
print(bukhari.id); // "6216"
print(bukhari.name); // "صحيح البخاري"
// Use in filters
final params = HadithSearchParams(
value: 'الزكاة',
page: 1,
books: [
BookReference.sahihBukhari,
BookReference.sahihMuslim,
],
);
// Get numeric id if needed
final bukhariId = int.parse(BookReference.sahihBukhari.id);
RawiReference (Narrators)
Note: There are ~14,000 narrators in the database, so only some companions are provided as constants.
// 20 companions
RawiReference.all // All (no filter)
RawiReference.abuHurayrah // Abu Hurayrah (1416)
RawiReference.aisha // Aishah (6617)
RawiReference.ibnAbbas // Ibn Abbas (2664)
RawiReference.ibnUmar // Abdullah b. Umar (7687)
RawiReference.anasBinMalik // Anas b. Malik (2177)
RawiReference.jabirIbnAbdullah // Jabir b. Abdullah (3971)
RawiReference.abuSaidKhudri // Abu Sa'id al-Khudri (779)
RawiReference.ibnMasud // Abdullah b. Mas'ud (7918)
RawiReference.abuMusaAshari // Abu Musa al-Ash'ari (1342)
RawiReference.umarIbnKhattab // Umar b. al-Khattab (8918)
RawiReference.aliIbnAbiTalib // Ali b. Abi Talib (8637)
RawiReference.abuBakr // Abu Bakr al-Siddiq (455)
RawiReference.uthmanIbnAffan // Uthman b. Affan (8310)
RawiReference.salmanFarisi // Salman al-Farisi (5947)
RawiReference.muadhIbnJabal // Mu'adh b. Jabal (10349)
RawiReference.abuDharr // Abu Dharr al-Ghifari (667)
RawiReference.bilal // Bilal b. Rabah (3808)
RawiReference.zaydIbnThabit // Zayd b. Thabit (5545)
RawiReference.ubayyIbnKab // Ubayy b. Ka'b (1695)
RawiReference.abuAyyub // Abu Ayyub al-Ansari (129)
// Each value has id and name
final abuHurayrah = RawiReference.abuHurayrah;
print(abuHurayrah.id); // "1416"
print(abuHurayrah.name); // "أبو هريرة"
// Use in filters
final params = HadithSearchParams(
value: 'الجنة',
page: 1,
rawi: [RawiReference.abuHurayrah],
);
// Get numeric id if needed
final abuHurayrahId = int.parse(RawiReference.abuHurayrah.id);
// To find more narrators, use the search service
final narrators = await client.rawiRef.searchRawi('عبد الله', limit: 10);
Seeing "Unclosed database" Warning? #
Always call client.dispose():
final client = DorarClient();
try {
// Use the library
} finally {
await client.dispose(); // Mandatory
}
Contributing #
All forms of contributions are welcome.
License #
MIT License - see LICENSE file.
Architecture #
DorarClient (Facade)
├── HadithService
├── SharhService
├── BookService
├── MohdithService
├── MohdithRefService
├── BookRefService
└── RawiRefService
└── HTTP Client + Cache
└── HTML Parsers
— May Allah reward us and you.