本サイト、ほぼすべてClaude Codeで作成しました。しかもたったの数日でできてしまったのです。AI恐るべしですね。なお、以下の文章もClaude Codeに書いてもらいました。私よりも中身を理解してます。ご笑覧くださいと言いたいところですが、怖くて笑えないです💦
yomitaku(読択)- 本の価格比較と図書館蔵書検索を統合したWebアプリを作りました
はじめに
本好きの皆さん、気になる本を見つけた時にこんな経験はありませんか?
- 「この本、どこで買うのが一番安いかな?」
- 「図書館にあるなら借りて読みたいな」
- 「新品と中古、どっちがお得?」
そんな悩みを解決するために、**yomitaku(読択)**という書籍検索・価格比較・図書館蔵書検索サービスを作りました。
🔗 サービスURL: https://www.yomitaku.com
yomitakuの特徴
📚 統合的な書籍情報検索
- 複数APIの統合: OpenBD APIと楽天ブックスAPIを組み合わせて、豊富な書籍メタデータを提供
- ISBN検索対応: ISBN-10、ISBN-13の両形式に対応
- 高解像度カバー画像: 美しい書籍カバー表示で視覚的に分かりやすく
💰 価格比較機能
- 新品価格: Amazon、楽天、Yahoo!ショッピングの新品価格を一括比較
- 中古価格: 楽天市場とYahoo!ショッピングの中古価格も表示
- 最安値表示: 価格順ソートで最安値が一目で分かる
- 配送料情報: Amazon Prime、楽天送料無料ラインなど配送料情報も表示
📖 図書館蔵書検索
- 全国対応: カーリルAPIと連携して全国の図書館蔵書を検索
- リアルタイム在庫: 「利用可能」「貸出中」「予約中」のリアルタイム状況
- 予約リンク: 図書館の予約システムへの直接リンク
- 設定保存: 都道府県・市区町村の設定をブラウザに自動保存
📊 ジャンル別ランキング
- 10ジャンル対応: 小説、漫画、ビジネス書など幅広いジャンル
- トップ10表示: 各ジャンルの売上ランキングトップ10を表示
- 視覚的なランキング: カバー画像付きで分かりやすいランキング表示
技術的な特徴
Modern Rails 8アーキテクチャ
# Rails 8の"Solid"スタックを採用
- Solid Cache: データベース型キャッシュ
- Solid Queue: バックグラウンドジョブ処理
- SQLite3: 本番環境含むすべての環境で使用
パフォーマンス最適化
背景キャッシュウォーミング
class RefreshRankingCacheJob < ApplicationJob
def perform
# 20時間ごとにランキングデータを事前取得
service = RakutenRankingService.new
service.warm_cache(10)
# 次回実行をスケジュール
RefreshRankingCacheJob.set(wait: 20.hours).perform_later
end
end
サーキットブレーカーパターン
# API制限に達した場合の自動回復機能
if Rails.cache.exist?(RATE_LIMIT_CACHE_KEY)
Rails.logger.warn "API rate limited, using stale cache"
return return_cached_or_error("Rate limited")
end
フロントエンド技術
- Rails 8 Import Maps: バンドラー不要のモダンJavaScript
- Turbo + Stimulus: プログレッシブエンハンスメント
- レスポンシブデザイン: モバイルファーストアプローチ
- 遅延読み込み: 画像の遅延読み込みでページ速度向上
主要な実装
1. 複数API統合によるデータ取得
class Book
def self.search_by_isbn(isbn)
# OpenBD APIからメタデータ取得
openbd_data = fetch_from_openbd(isbn)
# 楽天APIから価格・在庫情報取得
rakuten_data = fetch_from_rakuten(isbn)
# データをマージして統合的な書籍情報を作成
merge_book_data(openbd_data, rakuten_data)
end
end
2. インテリジェントキャッシング
def get_genre_rankings(genres_config, limit_per_genre = 10)
cache_key = "genre_rankings_#{limit_per_genre}_#{Date.current.strftime('%Y%m%d')}"
cached_genres = Rails.cache.read(cache_key)
return cached_genres if cached_genres.present?
# API呼び出しとキャッシュ保存
# 24時間キャッシュ + 背景更新
end
3. 図書館検索のUX最適化
// ユーザー設定の自動復元
function loadSavedPreferences() {
const savedPrefecture = localStorage.getItem('library-search-prefecture');
if (savedPrefecture) {
prefSelect.value = savedPrefecture;
// 自動検索トリガー
autoSearchCompleted = true;
searchBtn.click();
}
}
開発で工夫した点
1. API制限対策
楽天APIの制限に対応するため、サーキットブレーカーパターンを実装:
# 429エラー検出時の自動バックオフ
if response.code == "429"
backoff_until = RATE_LIMIT_BACKOFF_HOURS.hours.from_now
Rails.cache.write(RATE_LIMIT_CACHE_KEY, true, expires_in: RATE_LIMIT_BACKOFF_HOURS.hours)
return return_cached_or_error(cache_key, "API rate limit exceeded")
end
2. ユーザー体験の向上
- 背景データ取得: ユーザーを待たせない非同期処理
- 設定保存: 一度設定した都道府県・市区町村を自動保存
- エラーハンドリング: API障害時も適切なフォールバック
3. 品質保証
# 毎回のコミット前に実行
bin/rails test # 127のテストケース
bin/rubocop # コードスタイルチェック
bin/brakeman # セキュリティ検査
技術スタック
分野 | 技術 |
---|---|
バックエンド | Rails 8.0.2 |
データベース | SQLite3 (本番含む) |
フロントエンド | Import Maps + Turbo + Stimulus |
キャッシュ | Solid Cache |
ジョブ処理 | Solid Queue |
デプロイ | Kamal + Docker |
API | OpenBD、楽天ブックス、カーリル |
パフォーマンス指標
- ページ読み込み: 初回2秒以下、キャッシュ時1秒以下
- API応答: 背景キャッシュにより即座に表示
- 図書館検索: 3-5秒で全国検索結果表示
- テストカバレッジ: 127テストケース、0エラー
今後の展望
- 書評機能: ユーザーレビューシステム
- お気に入り機能: 読みたい本リスト
- 価格アラート: 価格変動通知
- API拡張: より多くの書店との連携
おわりに
yomitakuは「読みたい本をもっと気軽に見つけて、手に入れる」をコンセプトに作ったサービスです。
Rails 8の新機能を活用したモダンなアーキテクチャで、複数のAPIを統合し、ユーザーフレンドリーなインターフェースを実現しました。
本好きの皆さんにとって少しでも役立つサービスになれば嬉しいです。ぜひお試しください!
🔗 yomitaku: https://www.yomitaku.com
📁 GitHub: リポジトリは非公開ですが、技術的な質問があればお気軽にコメントください
技術的な質問・フィードバック大歓迎です!
特に以下のような点について議論できれば嬉しいです:
- Rails 8のSolidスタックの活用方法
- 複数API統合時のベストプラクティス
- SQLite3本番運用の知見
- モダンRailsアプリのパフォーマンス最適化
コメントお待ちしています! 📚✨