概要
- 【参考】親記事
書籍検索APIの選定に関する話です。iOSアプリ「ほんとも」では書籍検索に2つのAPIを使用しています。本記事ではどのような経緯で書籍検索APIを選定したのかを記事にしました。
登場する API 一覧
本記事で扱う API は全部で4つ。先に結論からお伝えすると、当初は使いやすさの観点からGoogle Books APIとOpenBDを選んでいましたが、途中で楽天ブックスとNDLサーチに乗り換えました。
採用したAPI
楽天ブックス API
| ポイント | 詳細 |
|---|---|
| ISBN の一意管理 | 書籍情報(電子、文庫、ハードカバー)が1つに集約されており、検索結果に重複がない |
| 和書カバー率 | 国内流通書籍に特化したデータベースのため、日本語書籍の収録漏れが少ない |
| 取得件数 | 1リクエストあたり最大30件(Google Books の20件より多い) |
※利用には楽天デベロッパーアカウントへの登録と Application ID・Access Key が必要
国立国会図書館サーチ(NDLサーチ)
| ポイント | 詳細 |
|---|---|
| NDC ジャンル | NDC(日本十進分類法)コードを提供しており、ジャンルフィルタ機能の実装に不可欠 |
| ライセンス表記 | 商用利用には利用規約の確認とアプリ内表記が必要 |
見送ったAPI
Google Books API
| 問題点 | 詳細 |
|---|---|
| 書籍の重複 | 書籍が電子書籍版、文庫版、ハードカバー版それぞれ個別で存在する |
| 和書カバー率の低さ | 国内流通書籍の収録漏れが多い |
OpenBD
| 問題点 | 詳細 |
|---|---|
| ジャンル情報の欠如 | NDC コードなどのジャンル分類情報を提供していない |
著者名・出版社の補完精度は問題なかったが、ジャンル情報取得のために NDLサーチへの移行を決めました。
背景
当時、利用ハードルの低さから、書籍検索にGoogle Books APIとOpenBDを使用しており、その中で以下の課題がありました。
【課題1】和書重複・カバー率
-
書籍の重複表示:
Google Books APIにおいて、電子版、文庫版、ハードカバー版など検索結果に同じ本が何冊も並ぶ。 - 和書カバー率の低さ: 国内流通の一般的な書籍が検索にヒットしないケースがあった。
【課題2】書籍ジャンルが取得できない
- 書籍登録時の情報補完(著者名・出版社)に OpenBD を使用していました。本棚のジャンルフィルタ機能を追加するにあたり、
Google Books APIやOpenBDはジャンル情報(NDC コード)を提供していないため、別の API への移行が必要になりました。
ゴール: ISBN が一意に管理され、和書の収録率が高い API に移行し、書籍ジャンルでのフィルタ機能を実現する。
どうやって解決したのか
利用時の注意点
まず、楽天ブックスAPIについて、こちらはRakuten DevelopersからアプリIDを発行し、アプリケーションIDとアクセスキーの2つを取得しておく必要があります。こちらは認証情報なので.envなどで管理した方が良いかと思います。
一方、NDLサーチAPIを用いた書籍検索は以下のAPI仕様を参考にしました。また、レスポンスのパース処理について一部設定が必要な箇所がありました。
- NDLサーチのAPI仕様
- NDLサーチの実行例(本を読む本を検索した場合)
NDLサーチAPIのレスポンスのパース処理
私の場合、NDLサーチは検索用APIとしてOpenSearchを利用しており、レスポンスは XML(RSS 2.0)形式でした。そこで、fast-xml-parser でパースしました。ここで、parseTagValue: false を忘れると NDC コードが崩れることに注意が必要です。例えば、NDC コードの "007.63" が 7.63(数値)に変換され、先頭ゼロが失われます。
import { XMLParser } from 'fast-xml-parser';
// ❌ デフォルト設定(parseTagValue が true)
const parser = new XMLParser({ ignoreAttributes: false });
// "007.63" → 7.63(数値)になり、先頭ゼロが消える
// ✅ parseTagValue: false で数値変換を無効化
const parser = new XMLParser({
ignoreAttributes: false,
parseTagValue: false, // "007.63" を文字列のまま保持
});
【補足】NDCコード→ジャンル名へのマッピング
NDC Navi を参考にマッピングを作成しています。NDC→ジャンル名の変換処理を用意し、画面表示する際はNDC→ジャンル名変換します。参考までに下表とそれを用いたサンプルコードを共有します。
| NDC | ジャンル |
|---|---|
| 0 | 総記 |
| 1 | 哲学・心理学 |
| 2 | 歴史・地理 |
| 3 | 社会科学 |
| 4 | 自然科学 |
| 5 | 技術・工学 |
| 6 | 産業 |
| 7 | 芸術・スポーツ |
| 8 | 言語 |
| 9 | 文学 |
const NDC_MAP: Record<string, string> = {
'0': '総記',
'1': '哲学・心理学',
'2': '歴史・地理',
'3': '社会科学',
'4': '自然科学',
'5': '技術・工学',
'6': '産業',
'7': '芸術・スポーツ',
'8': '言語',
'9': '文学',
};
export function ndcToGenre(code: string): string {
return NDC_MAP[code.charAt(0)] ?? 'その他';
}
【参考】書籍ジャンルの取得
感想
今回、国内向けに和書を幅広く取り扱える、かつ、書籍ジャンルを取得できるという観点から楽天ブックスAPIとNDLサーチAPIの2つを結果的に採用しました。また、Google Books APIでは電子版、文庫版などで同じ書籍データを取得できるため、重複削除のロジックが必要になることや、NDLサーチの実装では parseTagValue: false の見落としが典型的なハマりどころだったことなど、書籍検索のAPI選定で勉強になることが多くありました。
最後までお読みいただきありがとうございました。