Skip to main content

Overview

The Bible server actions provide functions to interact with the Bible API, including fetching available translations, retrieving books and chapters, and searching for verses. All functions are created using TanStack Start’s createServerFn() and include automatic validation using Zod schemas.

getBibles

Fetch all available Bible translations.
getBibles(): Promise<BibleSummary[]>

Returns

BibleSummary[]
array
Array of Bible translation summaries

Usage

import { getBibles } from '@/actions/bible'

export default function BibleSelector() {
  const [bibles, setBibles] = useState<BibleSummary[]>([])
  
  useEffect(() => {
    getBibles().then(data => {
      setBibles(data)
    })
  }, [])
  
  return (
    <select>
      {bibles.map(bible => (
        <option key={bible.id} value={bible.id}>
          {bible.name} ({bible.abbreviation})
        </option>
      ))}
    </select>
  )
}

Error Handling

If the API request fails, getBibles() returns an empty array [] instead of throwing an error. Errors are logged to the console.

getBooks

Retrieve all books for a specific Bible translation, including chapter information.
getBooks(params: { bibleId: string }): Promise<Book[]>

Parameters

bibleId
string
required
The unique identifier of the Bible translation (e.g., “de4e12af7f28f599-02”)

Returns

Book[]
array
Array of book objects with chapter information

Usage

import { getBooks } from '@/actions/bible'

export default function BookList({ bibleId }: { bibleId: string }) {
  const [books, setBooks] = useState<Book[]>([])
  
  useEffect(() => {
    getBooks({ bibleId }).then(data => {
      setBooks(data)
    })
  }, [bibleId])
  
  return (
    <div>
      {books.map(book => (
        <div key={book.id}>
          <h3>{book.name}</h3>
          <p>{book.chapters?.length || 0} chapters</p>
        </div>
      ))}
    </div>
  )
}

Error Handling

Returns an empty array [] if the request fails. Errors are logged to the console.

getChapter

Retrieve the full content of a specific chapter, including all verses and metadata.
getChapter(params: { 
  bibleId: string
  chapterId: string 
}): Promise<Chapter | null>

Parameters

bibleId
string
required
The unique identifier of the Bible translation
chapterId
string
required
The unique identifier of the chapter (e.g., “GEN.1”, “JHN.3”)

Returns

Chapter
object | null
Chapter object with full content, or null if not found

Usage

import { getChapter } from '@/actions/bible'
import { useEffect, useState } from 'react'

export default function ChapterReader({ 
  bibleId, 
  chapterId 
}: { 
  bibleId: string
  chapterId: string 
}) {
  const [chapter, setChapter] = useState<Chapter | null>(null)
  const [loading, setLoading] = useState(true)
  
  useEffect(() => {
    setLoading(true)
    getChapter({ bibleId, chapterId })
      .then(data => {
        setChapter(data)
      })
      .finally(() => setLoading(false))
  }, [bibleId, chapterId])
  
  if (loading) return <div>Loading...</div>
  if (!chapter) return <div>Chapter not found</div>
  
  return (
    <article>
      <h1>{chapter.reference}</h1>
      <div 
        className="chapter-content"
        dangerouslySetInnerHTML={{ __html: chapter.content }}
      />
      <footer>
        <p>{chapter.copyright}</p>
        <div className="navigation">
          {chapter.previous && (
            <a href={`/bible/${bibleId}/${chapter.previous.id}`}>
              Previous
            </a>
          )}
          {chapter.next && (
            <a href={`/bible/${bibleId}/${chapter.next.id}`}>
              Next
            </a>
          )}
        </div>
      </footer>
    </article>
  )
}

Error Handling

Returns null if the chapter cannot be found or the request fails. Errors are logged to the console.
The content property contains HTML markup. Always use dangerouslySetInnerHTML or a safe HTML sanitizer when rendering.

searchVerse

Search for verses matching a query string within a specific Bible translation.
searchVerse(params: {
  bibleId: string
  query: string
  offset: number
}): Promise<SearchResponse>

Parameters

bibleId
string
required
The unique identifier of the Bible translation to search within
query
string
required
The search query string. Keywords will be matched against verse text. All keywords must be present in a verse for it to match.
offset
number
required
Pagination offset for results. Use 0 for the first page, 10 for the second page (with default limit), etc.

Returns

SearchResponse
object
Search results with matching verses

Usage

import { searchVerse } from '@/actions/bible'
import { useState } from 'react'

export default function BibleSearch({ bibleId }: { bibleId: string }) {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState<SearchResponse | null>(null)
  const [loading, setLoading] = useState(false)
  const [page, setPage] = useState(0)
  
  const handleSearch = async (offset = 0) => {
    if (!query.trim()) return
    
    setLoading(true)
    const data = await searchVerse({ 
      bibleId, 
      query: query.trim(), 
      offset 
    })
    setResults(data)
    setLoading(false)
  }
  
  const loadMore = () => {
    const nextOffset = (page + 1) * 10
    setPage(page + 1)
    handleSearch(nextOffset)
  }
  
  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search verses..."
      />
      <button onClick={() => handleSearch(0)} disabled={loading}>
        Search
      </button>
      
      {results && (
        <div>
          <p>Found {results.total} verses</p>
          {results.verses.map(verse => (
            <div key={verse.id}>
              <strong>{verse.reference}</strong>
              <p>{verse.text}</p>
            </div>
          ))}
          
          {results.verseCount > 0 && results.total > (page + 1) * 10 && (
            <button onClick={loadMore}>Load More</button>
          )}
        </div>
      )}
    </div>
  )
}

Error Handling

Returns an empty SearchResponse object with the following default values if the request fails:
{
  query: '<original query>',
  limit: 0,
  offset: 0,
  total: 0,
  verseCount: 0,
  verses: []
}
Errors are logged to the console.

Search Tips

  • All keywords in the query must be present in a verse for it to match
  • Order of keywords does not matter
  • Use wildcards: * for any character sequence, ? for single characters
  • The API default limit is 10 results per page
  • Use the offset parameter to paginate through results

Type Definitions

All server actions use types imported from @/types/responses. Key types include:
  • BibleSummary - Summary information about a Bible translation
  • Book - Book information with optional chapters
  • Chapter - Full chapter content with verses
  • SearchResponse - Search results with matching verses
  • SearchVerse - Individual verse in search results
  • Language - Language information
  • ChapterSummary - Basic chapter metadata
For complete type definitions, refer to /home/daytona/workspace/source/src/types/responses.ts:1.