(142) JavaScriptでISBNから書籍情報を取得する。

投稿者: | 2023年12月16日

87 views

1. やりたいこと

書籍の裏表紙にプリントされている ISBNコード の値から書籍情報を取得したい。
このための Web APIがいろいろなサイトで公開されている。

↓ ISBNコード ↓

今回は Google Book API を使って ISBN to 書籍情報 の変換処理を実現してみる。

2. やってみる

実装済みのページはこちら。
https://www.dogrow.net/hp/sample/00142/01/

(1) index.html

たったこれだけの画面だ。
・ISBNコードの入力欄
・ISBN to 書籍情報の変換実行ボタン
・取得結果の表示欄(赤枠内)

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
  <title>Blog No.142-01 Google Books API</title>
</head>
<body>
<input type="text" name="isbn" value="9784297126858" />
<input id="btnStartQuery"  type="button" value="Execute ISBN Query"  />
<div id="result"></div>
</body>
</html>

(2) style.css

装飾は特になし。
取得した書籍情報の表示欄を赤枠で囲っただけ。

#result{
  border:2px solid #F00;
}

(3) script.js

1行目:DOM生成通知にて処理を実装する。
8行目:ボタン押下時に起動するイベントハンドラを登録する。
12行目:fetch()を使ってHTTPリクエストを発行する。
13行目:【チェーン#1】受信データ引数として受け、これを JSONとして構文解析し、その結果を JavaScriptオブジェクト(A)に変換する。
14行目:【チェーン#2】(A)を引数として受け、これを関数内(アロー関数で記述)で処理する。
33行目:チェーン#1, #2で発生した例外をキャッチする。

document.addEventListener("DOMContentLoaded", function() {
  // 使用する DOM Objectを事前取得しておく。
  const btnStartQuery  = document.getElementById("btnStartQuery");
  const inpIsbn        = document.querySelector('input[name="isbn"]');
  const divResult      = document.getElementById("result");

  // [execute ISBN query]ボタン押下時のイベントハンドラを登録する。
  btnStartQuery.addEventListener("click", function() {
    // ISBNコード入力欄にセットされている値を取得する。
    let isbn = inpIsbn.value;
    // Google Books APIを使って書籍情報を取得する。
    fetch(`https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`)
      .then(resp => resp.json())
      .then(data => {
        // 書籍データの解析と表示
        if (data.items && data.items.length > 0) {
          var book = data.items[0].volumeInfo;
          console.log('book:', book);
          console.log('# of Authors:', book.authors.length);
          book.authors.forEach(function(e){
            console.log('Author:', e);     // 著者
          });
          divResult.innerHTML = `
              タイトル: ${book.title}<br />
              著者:     ${book.authors}<br />
              出版社:   ${book.publisher}
          `;
        } else {
          divResult.innerHTML = `${isbn}の書籍情報が見つかりませんでした。`;
          console.log('No book found with that ISBN.');
        }
      })
      .catch(error => {
        console.error('Error fetching data:', error);
      });
  });
});

3. 補足説明

(1) 国立国会図書館の Web APIは JavaScriptからは使えない

Google Books APIの応答データを見ると、出版者やジャンルなどの情報が提供されないことが多い。
このため、書籍情報が充実している国会図書館のWeb APIを使いたいのだが…
CORS制約のため、国会図書館の Web APIを JavaScriptから利用できない。

CORS : Cross-Origin Resource Sharing ※コーズと発音する。
Origin : Webページのダウンロード元のドメイン、ポート番号、スキーム(http. https)のこと。

JavaScriptで国立国会図書館の Web APIにリクエストを送ると、具体的には以下のような動作をしている。
1.【Webブラウザ】JavaScriptから国会図書館 Web APIに対して HTTPリクエストを発行
2.【国会図書館Webサーバ】Web APIの応答データを返送
  ※このとき、HTTPレスポンスヘッダに Access-Control-Allow-Origin ヘッダが含まれていない。
3.【Webブラウザ】データを受信するが、HTTPレスポンスヘッダ内に CORS情報が無いため、これをユーザーアプリ(=JavaScriptプログラム)に渡さない。
  → Web APIが機能しないように見えている。

因みに、JavaScriptからの Web API実行が成功する場合、
Webサーバからの HTTPレスポンスヘッダ内に Access-Control-Allow-Origin: * が含まれている。

CORS(Cross-Origin Resource Sharing)については、以下のサイトを参照されたい。
https://aws.amazon.com/jp/what-is/cross-origin-resource-sharing/

CORS制約を回避して JavaScriptからの Web API利用を可能にするには?
策1:使っているWebブラウザのセキュリティ設定を緩和し、CORS制約をチェック無に設定変更する。 ※危険?
策2:サーバー管理者に HTTPレスポンスヘッダに CORS情報を埋め込むように依頼する。

(2) アロー関数から無名関数への置き換え

上記の script.js内の fetch()関数配下では、アロー関数を使用している。
これを無名関数で書き換えると以下のようになる。

Before : アロー関数

fetch("http://example.com/webapi")
  .then(resp => resp.json())
  .then(data => {
    // do something
    // 次に連鎖させるならば、retunで Promiseオブジェクトを返すこと。
  })
  .catch(error => {
    // do something
  });
});

After : 無名関数

fetch("http://example.com/webapi")
  .then(function(resp){
    // retunで JSON解析結果を bodyに持つ Responseオブジェクトを返す。→ 次に連鎖
    return resp.json();
  })
  .then(function(data){
    // do something
    // 次に連鎖させるならば、retunで Promiseオブジェクトを返すこと。
  })
  .catch(function(error){
    // do something
  });
});

(3) アロー関数の引数と戻り値(単一式の場合)

アロー関数の本体が単一の式の場合、中括弧と return ステートメントを省略できる

const square = x => x * x;

以下と同じ。

function square(x){
  return x * x;
}

(4) アロー関数の引数と戻り値(複数のステートメントがある場合)

複数のステートメントとは、命令が複数行あるということ。
次の例では引数が 2個あるため、引数の宣言を () で囲む必要がある。

const add = (x, y) => {
  const sum = x + y;
  return sum;
};

以下と同じ。

function add(x, y){
  const sum = x + y;
  return sum;
}

(5) JavaScriptの Promiseクラス

fetch関数は Promiseオブジェクトを返すため、.thenメソッドを使ってレスポンスを処理する。
MDN公式サイトの Promiseの説明はこちら ※要熟読

理解すべきポイントを以下に列挙する。(個人的な意見)

  • Promiseは、非同期処理の最終的な完了もしくは失敗を表すオブジェクトです。
  • Promiseは、コールバックを関数に渡すかわりに、関数が返した Promiseオブジェクトにコールバックを登録するものです。
  • 2つ以上の非同期処理を連続して実行することで、前回の処理が成功したときに、その結果をもとに後続の処理を始められます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)