139 lines
3.8 KiB
JavaScript
139 lines
3.8 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const helmet = require('helmet');
|
|
const path = require('path');
|
|
const fs = require('fs').promises;
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
// Middleware
|
|
app.use(helmet({
|
|
contentSecurityPolicy: false,
|
|
crossOriginOpenerPolicy: false,
|
|
crossOriginEmbedderPolicy: false,
|
|
originAgentCluster: false
|
|
}));
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
// Serve static files from the React build
|
|
app.use(express.static(path.join(__dirname, '../../frontend/build')));
|
|
|
|
// Bible data directory
|
|
const BIBLE_DATA_DIR = path.join(__dirname, '../../bible-data');
|
|
|
|
// Helper function to read markdown files
|
|
async function readMarkdownFile(filePath) {
|
|
try {
|
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
return content;
|
|
} catch (error) {
|
|
throw new Error(`Failed to read file: ${filePath}`);
|
|
}
|
|
}
|
|
|
|
// Helper function to get all books
|
|
async function getBooks() {
|
|
try {
|
|
const items = await fs.readdir(BIBLE_DATA_DIR);
|
|
const bookDirs = [];
|
|
|
|
for (const item of items) {
|
|
const itemPath = path.join(BIBLE_DATA_DIR, item);
|
|
const stat = await fs.stat(itemPath);
|
|
|
|
if (stat.isDirectory()) {
|
|
// Check if directory contains markdown files
|
|
try {
|
|
const files = await fs.readdir(itemPath);
|
|
if (files.some(file => file.endsWith('.md'))) {
|
|
bookDirs.push(item);
|
|
}
|
|
} catch (error) {
|
|
// Skip directories we can't read
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bookDirs;
|
|
} catch (error) {
|
|
throw new Error('Failed to read bible data directory');
|
|
}
|
|
}
|
|
|
|
// Routes
|
|
app.get('/health', (req, res) => {
|
|
res.json({ status: 'OK', message: 'ESV Bible API is running' });
|
|
});
|
|
|
|
app.get('/books', async (req, res) => {
|
|
try {
|
|
const books = await getBooks();
|
|
res.json({ books });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
app.get('/books/:book', async (req, res) => {
|
|
try {
|
|
const { book } = req.params;
|
|
const bookDir = path.join(BIBLE_DATA_DIR, book);
|
|
|
|
// Check if book directory exists
|
|
const stat = await fs.stat(bookDir);
|
|
if (!stat.isDirectory()) {
|
|
return res.status(404).json({ error: `Book '${book}' not found` });
|
|
}
|
|
|
|
// Get all chapter files
|
|
const files = await fs.readdir(bookDir);
|
|
const chapterFiles = files.filter(file => file.endsWith('.md')).sort();
|
|
|
|
if (chapterFiles.length === 0) {
|
|
return res.status(404).json({ error: `No chapters found for book '${book}'` });
|
|
}
|
|
|
|
// Extract chapter numbers from filenames (e.g., "Chapter_01.md" -> "1")
|
|
const chapters = chapterFiles.map(file => {
|
|
const match = file.match(/Chapter_(\d+)\.md$/);
|
|
return match ? parseInt(match[1], 10).toString() : null;
|
|
}).filter(Boolean);
|
|
|
|
res.json({ chapters });
|
|
} catch (error) {
|
|
res.status(404).json({ error: `Book '${req.params.book}' not found` });
|
|
}
|
|
});
|
|
|
|
app.get('/books/:book/:chapter', async (req, res) => {
|
|
try {
|
|
const { book, chapter } = req.params;
|
|
const chapterPath = path.join(BIBLE_DATA_DIR, book, `${chapter}.md`);
|
|
|
|
const content = await readMarkdownFile(chapterPath);
|
|
res.type('text/markdown').send(content);
|
|
} catch (error) {
|
|
res.status(404).json({ error: `Chapter ${chapter} not found in book '${book}'` });
|
|
}
|
|
});
|
|
|
|
// Catch-all handler: send back React's index.html for client-side routing
|
|
app.get('*', (req, res) => {
|
|
res.sendFile(path.join(__dirname, '../../frontend/build/index.html'));
|
|
});
|
|
|
|
// Error handling middleware
|
|
app.use((err, req, res, next) => {
|
|
console.error(err.stack);
|
|
res.status(500).json({ error: 'Something went wrong!' });
|
|
});
|
|
|
|
// Start server
|
|
app.listen(PORT, () => {
|
|
console.log(`ESV Bible API server running on port ${PORT}`);
|
|
console.log(`Bible data directory: ${BIBLE_DATA_DIR}`);
|
|
});
|