কোটলিন
Kotlin SDK packages/free-use-bible-api-kotlin এ থাকে।
Kotlin client for the public Free Use Bible API:
https://bible.helloao.org
It works on the JVM (Java 8+) and Android, uses kotlinx.serialization for the response models, and exposes every request as a suspend function.
Installation
The library isn't published to Maven Central yet. To use it, build it from source and install it into your local Maven repository:
git clone https://github.com/HelloAOLab/bible-api.git
cd bible-api/packages/free-use-bible-api-kotlin
./gradlew publishToMavenLocalThen add it to your project:
// build.gradle.kts
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation("org.helloao:free-use-bible-api:1.15.0")
}Quick Start
import kotlinx.coroutines.runBlocking
import org.helloao.freeusebibleapi.FreeUseBibleApi
fun main() = runBlocking {
val api = FreeUseBibleApi()
val available = api.getAvailableTranslations()
println("Total translations: ${available.translations.size}")
val books = api.getTranslationBooks("BSB")
println("Books in BSB: ${books.books.size}")
val chapter = api.getTranslationBookChapter("BSB", "GEN", 1)
println("Verses in Genesis 1: ${chapter.numberOfVerses}")
println(api.getChapterVerseText(chapter))
}Client Options
import org.helloao.freeusebibleapi.FreeUseBibleApi
import org.helloao.freeusebibleapi.UrlConnectionHttpClient
val api = FreeUseBibleApi(
endpoint = "https://bible.helloao.org/",
useCache = true,
httpClient = UrlConnectionHttpClient(connectTimeoutMillis = 10_000, readTimeoutMillis = 30_000),
)endpoint: Base API endpoint.useCache: Enables in-memory response caching (default:true). Concurrent requests for the same URL share a single HTTP request.httpClient: TheFreeUseBibleApiHttpClientused to make requests. The default (UrlConnectionHttpClient) usesHttpURLConnection, so the library has no dependencies besides kotlinx.serialization and kotlinx.coroutines.
To use a different HTTP library (like OkHttp or Ktor), implement FreeUseBibleApiHttpClient:
val api = FreeUseBibleApi(httpClient = { url ->
val response = myHttpClient.get(url)
FreeUseBibleApiHttpResponse(response.code, response.message, response.bodyAsText())
})Every request method also accepts an optional endpoint argument that overrides the client's endpoint for that request.
API Methods
Translations
getAvailableTranslations(endpoint?)getTranslationBooks(translation, endpoint?)getTranslationBookChapter(translation, book, chapter, endpoint?)getTranslationBookChapterAudioTimings(translation, book, chapter, reader, endpoint?)getTranslationBookChapterWords(translation, book, chapter, endpoint?)getCompleteTranslation(translation, endpoint?)getSimpleTranslationBookChapter(translation, book, chapter, endpoint?)getSimpleTranslationBookChapterWords(translation, book, chapter, endpoint?)getSimpleCompleteTranslation(translation, endpoint?)
getCompleteTranslation() and getSimpleCompleteTranslation() are never cached because their responses are very large.
Only some chapters have audio timings. The keys of a chapter's thisChapterAudioTimings property identify the readers available to pass to getTranslationBookChapterAudioTimings().
Commentaries
getAvailableCommentaries(endpoint?)getCommentaryBooks(commentary, endpoint?)getCommentaryBookChapter(commentary, book, chapter, endpoint?)getSimpleCommentaryBookChapter(commentary, book, chapter, endpoint?)
Datasets
getAvailableDatasets(endpoint?)getDatasetBooks(dataset, endpoint?)getDatasetBookChapter(dataset, book, chapter, endpoint?)- returns anApiDatasetBookChapterResult, which is either anApiDatasetBookChapter(the cross references for cross reference datasets, or the original-language words of each verse for interlinear datasets such asbsb-interlinear) or anApiDatasetEntityBookChapter(the people, places, and events that appear in the chapter for entity datasets such astheographic).getDatasetPeople(dataset, endpoint?)getDatasetPerson(dataset, person, endpoint?)getDatasetPlaces(dataset, endpoint?)getDatasetPlace(dataset, place, endpoint?)getDatasetEvents(dataset, endpoint?)getDatasetEvent(dataset, event, endpoint?)getDatasetPeopleGroups(dataset, endpoint?)getDatasetPeopleGroup(dataset, group, endpoint?)getDatasetLexicon(dataset, endpoint?)getDatasetLexiconEntry(dataset, strongs, endpoint?)getDatasetVerses(dataset, endpoint?)getVerseOfTheDay(date?, seed?, category?, dataset?, endpoint?)getDatasetCategories(dataset, endpoint?)getDatasetCategory(dataset, category, endpoint?)
Chapter Navigation Helpers
getNextChapter(chapter, endpoint?)/getPreviousChapter(chapter, endpoint?)- accept any kind of chapter (translation, simplified translation, commentary, simplified commentary, or dataset) and return a chapter of the same kind, ornullif there isn't one.getFirstChapter(book, endpoint?)/getLastChapter(book, endpoint?)- accept a translation, commentary, or dataset book.
Chapter & Verse Helpers
formatReference(book, reference)- formats aVerseReferenceas a string likeGenesis 1:1-3.getVerseText(verse)- gets the plain text of a verse.getChapterVerseText(chapter, omitVerseNumbers = false, omitReference = false)- gets the plain text of a chapter.
Word Annotations
Some translations include word-level annotations (Strong's numbers and related source data) for their chapters.
getChapterWords(chapter, endpoint?)- gets the annotations for a chapter you already loaded, ornullif it doesn't have any.getWordText(verse, word)- gets the text that a single annotation applies to.getVerseWords(verse, words)- gets the annotations for a verse, each paired with the text it applies to.
Each annotation is anchored to a range of characters in a single item of a verse's content list: contentIndex is the index of the item, and start/end are character offsets into that item's text (end is exclusive). getWordText() and getVerseWords() resolve those offsets for you.
Simplified Chapters
Every translation and commentary chapter can also be fetched in a simplified format, where each verse's content is a single string instead of a list of formatted content. Footnotes, inline headings, the Words of Jesus, and poetry are represented as offset ranges into that string.
getSimpleTranslationBookChapter(translation, book, chapter, endpoint?)getSimpleCommentaryBookChapter(commentary, book, chapter, endpoint?)getSimpleCompleteTranslation(translation, endpoint?)getSimpleChapter(chapter, endpoint?)- follows a chapter'ssimpleChapterApiLink, or returnsnullif simplified chapters aren't available for it.getSimpleTranslationBookChapterWords(translation, book, chapter, endpoint?)/getSimpleChapterWords(chapter, endpoint?)- the same as the regular word annotations, but with offsets into the simplified verse text.getSimpleWordText(verse, word)/getSimpleVerseWords(verse, words)- the same asgetWordText()/getVerseWords(), but for simplified verses.getSimpleChapterVerseText(chapter, omitVerseNumbers = false, omitReference = false)- the same asgetChapterVerseText(), but for a simplified chapter.
Working With Chapter Content
Chapter content is modeled with sealed interfaces, so you can use when to handle each kind of content:
val chapter = api.getTranslationBookChapter("BSB", "PSA", 23)
for (content in chapter.chapter.content) {
when (content) {
is ChapterHeading -> println("## ${content.content.joinToString(" ")}")
is ChapterVerse -> println("${content.number}: ${api.getVerseText(content)}")
is ChapterHebrewSubtitle -> println("(${content.content.size} subtitle parts)")
is ChapterLineBreak -> println()
// Content types added in newer API versions decode as UnknownChapterContent.
is UnknownChapterContent -> Unit
}
}The items in a verse's content are VerseContents: PlainText, FormattedText, InlineHeading, InlineLineBreak, VerseFootnoteReference, or UnknownVerseContent. ChapterLineBreak and InlineLineBreak have a paragraph property with the source paragraph marker (such as p or m) when the break starts a new paragraph.
Examples
Read a dataset chapter
when (val chapter = api.getDatasetBookChapter("theographic", "GEN", 1)) {
is ApiDatasetEntityBookChapter -> chapter.chapter.people.forEach { println(it.name) }
is ApiDatasetBookChapter -> println("${chapter.numberOfReferences} references")
}Read the Strong's numbers for a chapter
val chapter = api.getTranslationBookChapter("engwebp", "JHN", 1)
val words = api.getChapterWords(chapter) ?: return // No word-level annotations.
for (verse in chapter.chapter.content.filterIsInstance<ChapterVerse>()) {
for (word in api.getVerseWords(verse, words)) {
println("${word.text} ${word.word.strongs}")
}
}Error Handling
Requests that return a non-2xx status code throw a FreeUseBibleApiException, which includes the url, statusCode, and statusMessage of the response. Failed requests are not cached.
A 404 response usually means one of the path values is invalid, for example the translation, commentary, dataset, book, or chapter.
Notes
- String enums in the API (such as
textDirectionandlanguage) are represented asStrings so that new values don't break existing apps. - Unknown properties in responses are ignored, so newer versions of the API stay compatible with older versions of the library.
FreeUseBibleApi.jsonis theJsoninstance used to parse responses, if you want to parse API files yourself.