JavaScript フェッチ API について
フェッチ?? API?? なんかわからない言葉がでてきたぞ真剣に聞くぞという顔をしている柴犬です。
概要
AJAXというものを最近始めてみました。どういうものか調べてみました。
まず、次の公式HPで「AJAX」を見てみました。
https://developer.mozilla.org/ja/docs/Glossary/AJAX
それによると、AJAXは XMLHttpRequest という技術を用いて、ウェブページを構築するプログラミング手法のことのようです。
そして、対話型のウェブサイトや最新のウェブ標準では、AJAX は徐々に Fetch API 標準に置き換えられていると記述されています。
つまり、Fetch API は XMLHttpRequest API をより柔軟で強力な機能を備えたものに置き換えたものとありますので、今日 AJAX は敢えて使われていないようです。
XMLHttpRequest API
XMLHttpRequest API を次の公式HPで調べてみます。
https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest_API
WEBアプリケーションがWEBサーバーにJavaScript プログラムで HTTP リクエストを行い、JavaScript プログラムでレスポンスを受け取るために使われるAPIのようです。
使用方法
- XMLHttpRequest のインスタンスを、コンストラクターを呼び出して作成します。
- XMLHttpRequest.open(リクエストの URL, HTTP メソッド, オプションでユーザ名ー, パスワード ) を呼び出して初期化します。
- リクエストの結果を取得するイベントハンドラーを取り付けます。
- XMLHttpRequest.send() を呼び出してリクエストを送信します。
Fetch API
フェッチ API は(ネットワーク越しの通信を含む)リソース取得のためのインターフェイスを提供しています。
fetch() メソッド init オブジェクト
fetch() はグローバルメソッドで、ネットワークからリソースを取得するプロセスを開始し、レスポンスが利用できるようになったら履行されるプロミス(Promise オブジェクト)を返します。
必須の引数は1つで取得したいリソースのパスを指定します。
2 つ目の引数を適用することができ、init オブジェクトで様々な種類の設定を制御することができます。
init オブジェクトの中身を見てみると
fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json",
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "follow", // manual, *follow, error
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data), // 本体のデータ型は "Content-Type" ヘッダーと一致させる必要があります
})
からコメントアウトを削除すると
fetch(url, {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
referrerPolicy: "no-referrer",
body: JSON.stringify(data),
})
更に絞り込むと次のようになります。
init オブジェクト
{
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
referrerPolicy: "no-referrer",
body: JSON.stringify(data),
}
Request オブジェクト
Request は fetch API のインターフェイスで、リソースのリクエストを表します。
次のよう Request も可能です。
const request = new Request("https://example.com", {
method: "POST",
body: '{"foo": "bar"}',
});
const url = request.url;
const method = request.method;
const credentials = request.credentials;
const bodyUsed = request.bodyUsed;
Request オブジェクトを、 fetch() 呼び出しの引数として渡すことで API リクエストを取得でき、かつレスポンスを取得できます。
つまり、次のようにすることができます。
fetch(request)
.then((response) => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("Something went wrong on API server!");
}
})
.then((response) => {
console.debug(response);
// …
})
.catch((error) => {
console.error(error);
});
Response オブジェクト
Response オブジェクトから JSON の本体の内容を抽出するには json() メソッドを使用します。これは Response 本体のテキストを JSON として解釈して第2のPromise オブジェクトを返します。
使用例
async function Movies() { const response = await fetch("http://hogehoge.com/movies.json"); const movies = await response.json(); console.log(movies); }
then を使ってみる
上のコードをチェーンメソッドで続けて書けるようです。
fetch("http://hogehoge.com/movies.json") .then((response) => response.json()) .then((movies) => console.log(movies));
body: JSON.stringify(data)
init オブジェクトの中でいつも手間がかかるのが JSON.stringify(data) で data が重なってくると大カッコ(ブラケット)、中カッコ(ブレース)、小カッコの開き閉じで混乱することが間々あります。
配列、Mapオブジェクトで組み合わせて少し考えてみたのが次のものです。
JSON文字列への変換1
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form> <input type="button" id="run" value="実行" onclick="test()" /> <input type="text" id="location" size="10" /> </form> <p id="json" style="width: 900px; word-wrap: break-word;"></p> <script language="javascript" type="text/javascript"> function test() { //testデータの作成 const readdata = []; for (let i = 1; i <= 50; i++) { let text = "0000000000" + i; //"DATA" + 10桁の数字 readdata.push("DATA" + text.substring(text.length - 10)); } console.log(readdata); //テキストボックスの値を取得 const mylocation = document.getElementById("location").value console.log(mylocation); //データ構造の作成 const midasi = ["field1", "field2", "field3", "field4", "field5", "field6", "field7", "field8", "field9", "field10", "field11", "field12", "field13", "field14", "field15"]; //一つのMapオブジェクトに15個のデータペアを作成 const map1 = new Map(); const map2 = new Map(); const map3 = new Map(); const map4 = new Map(); const map5 = new Map(); const map6 = new Map(); const map7 = new Map(); const map8 = new Map(); // const list = [map1, map2, map3, map4, map5, map6, map7, map8]; //既定の数値 const midasilen = midasi.length; const readdatalen = readdata.length; const totallen = midasilen * list.length; //データ構造体の作成 for (let i = 0; i < totallen; i++){ //iの属するlistのインデックスを求める let j = Math.floor(i / midasilen); if (i < readdatalen) { //iの属するmidasiのインデックスは i % midasilen であるから list[j].set(midasi[i % midasilen] , readdata[i]); } else { list[j].set(midasi[i % midasilen], null); } } //データ構造体を2つに分ける const list1 = [Object.fromEntries(list[0]), Object.fromEntries(list[1]), Object.fromEntries(list[2]), Object.fromEntries(list[3])]; const list2 = [Object.fromEntries(list[4]), Object.fromEntries(list[5]), Object.fromEntries(list[6]), Object.fromEntries(list[7])] const mainmap = new Map(); mainmap.set("list1", list1); mainmap.set("list2", list2); document.getElementById("json").innerHTML = JSON.stringify(Object.fromEntries(mainmap)); } </script> </body> </html>
JSON文字列への変換2
//データ構造体の作成 for (let i = 0; i < totallen; i++) { //iの属するlistのインデックスを求める let j = Math.floor(i / midasilen); if (i < readdatalen) { let p = new Map(); p.set(keylist[0], readdata[i]); p.set(keylist[1], mylocation); //iの属するmidasiのインデックスは i % midasilen であるから list[j].set(midasi[i % midasilen], Object.fromEntries(p)); } else { list[j].set(midasi[i % midasilen], null); } }
どうやっても私は混乱しそうです。この件はここまでとします。