読みたい本がある。買う前に、エージェントに聞いた。「近所の図書館にある?」。数秒で返ってきた。「世田谷の中央図書館にはありますが、貸出中です」。蔵書の有無だけじゃなく、いま借りられるかどうかまで分かる。図書館はタダだ。この一手間で本代が浮く。
kurashi-skillの6つ目、calil-booksは、カーリル図書館APIで全国の図書館の蔵書と貸出状況を調べるスキルだ。公式APIで、利用は無料。公共の蔵書データが、図書館と連携する民間の無料APIを通じて市民に届く。僕はこの形が好きだ。
起: まず館を探す
蔵書照会には、図書館システムのID(systemid)が要る。都道府県や市区町村で図書館を検索して手に入れる。
curl -s "https://api.calil.jp/library?appkey=${CALIL_APPKEY}&pref=東京都&city=世田谷区&format=json&callback=no"
APIキーはカーリルのサイトで無料発行できる(最初の1回だけ)。キーはチャットやコミットに書かず、環境変数に入れる。検索結果には systemid(例: Tokyo_Setagaya)と、館の略名 libkey、正式名 formal が並ぶ。
承: 本の貸出状況を聞く
curl -s "https://api.calil.jp/check?appkey=${CALIL_APPKEY}&isbn=9784478025819&systemid=Tokyo_Setagaya&format=json&callback=no"
実際に打ってみた(2026-09-14実測)。初回の応答はこれだ。
{"session": "0a52...", "continue": 1, "books": {"9784478025819": {"Tokyo_Setagaya": {"status": "Running"}}}}
continue: 1 は「まだ集計中」の意味。返ってきた session を付けて2秒以上あけて再取得する。1回のポーリングで continue: 0 になり、館ごとの結果が出た。中央図書館は貸出中、梅丘図書館も貸出中……と並ぶ。状態は「貸出可」「蔵書なし」「貸出中」「予約中」「休館中」などで、reserveurl に予約ページのURLが入ることもある。
「貸出中」は少し残念だが、予約できる。情報があるのとないのとでは週末の過ごし方が変わる。
ちなみに systemid はカンマ区切りで複数指定できる。東京在住で「近くの図書館」とだけ言われたときのため、スキルには既定の照会先として、東京都立図書館(Tokyo_Pref)と23区全部の区立図書館のsystemid表を載せた(APIで実測確認済み)。例えば都立・世田谷・渋谷をまとめて1回で聞くならこうだ。
curl -s "https://api.calil.jp/check?appkey=${CALIL_APPKEY}&isbn=9784478025819&systemid=Tokyo_Pref,Tokyo_Setagaya,Tokyo_Shibuya&format=json&callback=no"
24館分を1回のポーリングで見られるので、区をまたいで「どこかにいる本」を探すのが一気に楽になる。
転: 2つの罠
このAPI、素直に見えて罠が2つある。
1つ目: format=json なのにJSONが返ってこない。 上の図書館検索から callback=no を外すと、応答は callback([...]) でラップされたJSONPになる。実際に試した。format=json と書いたのにだ。カーリル自身がJSONPは非推奨と案内しているが、既定はそちら側だ。jq にそのまま食わせると構文エラーになる。「JSONをください」と書いたのにJSONでないものが返る。仕様とはそういうものだと、最初の数バイトを自分の目で見るまで信じないことにした。
2つ目: 答えが非同期。 初回に continue: 1 が返る仕組みを知らないと、「status: Running」をエラーと勘違いする。かといって、終わるまで無限にポーリングするのも失格だ。スキルには上限を書いた。最大10回・合計2分程度。それを超えたら打ち切って、「図書館APIの照会が混み合っています。時間をおいてもう一度」とユーザーに伝える。粘りすぎないのも礼儀だ。
そして「蔵書なし」はエラーではない。その館に本がないという、正常な結果だ。空や否定を失敗と混同しない。
結: 持ち帰れる教訓3つ
-
format=jsonは約束ではない。 応答の最初の数バイトを自分で確認する。JSONPの罠はいまでも生きている。 -
非同期APIには上限つきポーリングを。
sessionを受け取り、間隔をあけ、回数と時間の上限を決め、打ち切ったときの言葉まで用意する。 - 「ない」も結果。 蔵書なし・空配列・0件は、失敗ではなく答え。取得失敗と分けて伝える。
kurashi-skillは公開開発中。リポジトリはここ → https://github.com/tahodev/kurashi-skill
結局その本は、返ってくるのを予約で待つことにした。本は買う前に、図書館に聞く。タダのAPIで、タダの本が見つかる。