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つ以上の非同期処理を連続して実行することで、前回の処理が成功したときに、その結果をもとに後続の処理を始められます。