JavaScript で API を呼び出す

JavaScriptBeginner
オンラインで実践に進む

はじめに

このラボでは、モダン JavaScript を使用して Web API とやり取りするための必須スキルを習得します。Web ブラウザに組み込まれている強力で柔軟なツールである fetch API を使用して、非同期ネットワークリクエストを行います。主な目標は、サーバーからデータをリクエストする方法、レスポンスを処理する方法、および潜在的なエラーを管理する方法を理解し、動的な Web アプリケーションを構築するための基礎スキルを形成することです。

まず、データを取得するための基本的な GET リクエストを行い、次にレスポンスの処理方法、JSON としての解析方法、そして取得したデータを HTML 要素内に表示する方法を学びます。このラボでは、堅牢なエラー処理の実装、サーバーにデータを送信するための POST リクエストの作成、API キーを使用したリクエストの認証といった重要な側面もカバーします。

fetch API で基本的な GET リクエストを行う

このステップでは、JavaScript で基本的な API コールである GET リクエストを行う方法を学びます。ここでは、すべてのモダンな Web ブラウザに組み込まれており、Node.js 18+ 環境でも利用可能な、モダンで強力かつ柔軟なツールである fetch API を使用します。これにより、サーバーからリソースを非同期的にリクエストできます。

fetch 関数は Promise ベースであり、リクエストが成功したかどうかにかかわらず、そのリクエストに対する Response に解決される Promise を返します。これにより、非同期操作が完了したときにその結果を処理できます。

まず、コードを記述するためのファイルを作成しましょう。画面左側のファイルエクスプローラーで、~/project ディレクトリに index.js という名前の新しいファイルを作成します。

この例では JSONPlaceholder API を使用します。これは、テストやプロトタイピングに最適な、無料のオンラインフェイク REST API です。ここでは、単一の「todo」アイテムをリクエストします。

次に、以下のコードを index.js ファイルに追加します。このコードは API エンドポイントの URL を定義し、fetch を使用して GET リクエストを行います。

// 単一の todo アイテムの API URL を定義します
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";

// fetch API を使用して GET リクエストを行います
fetch(apiUrl)
  .then((response) => {
    // fetch 関数は Promise を返します。
    // 最初の .then() ブロックは Response オブジェクトを受け取ります。
    // body テキストを JSON として解析するには、response の .json() メソッドを呼び出す必要があります。
    return response.json();
  })
  .then((data) => {
    // 2 番目の .then() ブロックは、解析された JSON データを受け取ります。
    console.log("Data fetched successfully:");
    console.log(data);
  })
  .catch((error) => {
    // .catch() ブロックは、fetch 操作中にエラーが発生した場合に実行されます。
    console.error("Error fetching data:", error);
  });

コードの内訳を見てみましょう。

  • apiUrl: 連絡を取りたい API エンドポイントの URL を定数に格納します。
  • fetch(apiUrl): これにより、指定された URL への GET リクエストが開始され、Promise が返されます。
  • .then(response => response.json()): Promise が解決されると、この関数が呼び出されます。response オブジェクトは実際の JSON データではなく、HTTP レスポンス全体を表すものです。response.json() メソッドを呼び出して、API からの JSON ボディコンテンツを抽出します。このメソッド自体も別の Promise を返します。
  • .then(data => { ... }): この 2 番目の .then() は、response.json() によって返された Promise を処理します。data パラメータには、API からの実際の JSON オブジェクトが含まれます。このデータをコンソールにログ出力します。
  • .catch(error => { ... }): どの時点でも Promise が拒否された場合(たとえば、ネットワークエラーのため)、このブロックがエラーをキャッチし、コンソールにログ出力します。

スクリプトを実行して結果を確認するには、WebIDE で新しいターミナルを開き、次のコマンドを実行します。

node ~/project/index.js

コンソールにフェッチされたデータが表示されるはずです。これは API からの単一の「todo」アイテムを表します。

期待される出力:

Data fetched successfully:
{ userId: 1, id: 1, title: 'delectus aut autem', completed: false }
JavaScript fetch API GET request example

レスポンスの処理と JSON データの解析

このステップでは、API コールからのレスポンスの処理についてさらに詳しく見ていきます。fetch を使用すると、サーバーは Response オブジェクトを返します。このオブジェクトに含まれるものと、そのボディから JSON データをアプリケーションで使用するために正しく解析する方法を探ります。

最初の .then() ブロックで受け取る Response オブジェクトは、データそのものではありません。これは、ステータスコード(OK の場合は 200 など)、ヘッダー、レスポンスボディを含む、HTTP レスポンス全体を表すものです。ボディはデータのストリームであり、それを使用するには読み取る必要があります。

fetch API は、プレーンテキスト用の .text() や JSON データを解析するための .json() など、このためのいくつかのメソッドを提供します。.json() メソッドはレスポンスストリームを最後まで読み取り、ボディテキストを JavaScript オブジェクトとして解析した結果に解決される新しい Promise を返します。そのため、実際のデータを扱うために 2 番目の .then() をチェーンします。

これを実証するために、~/project/index.js ファイルを更新しましょう。データオブジェクト全体をログ出力するだけでなく、そこから特定のプロパティにアクセスしてログ出力し、通常の JavaScript オブジェクトとして扱えることを示します。

~/project/index.js ファイルの内容を以下のコードで更新してください。

// 単一の todo アイテムの API URL を定義します
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";

fetch(apiUrl)
  .then((response) => {
    // response.json() メソッドは、レスポンスの JSON ボディを解析し、
    // 結果の JavaScript オブジェクトに解決される Promise を返します。
    return response.json();
  })
  .then((data) => {
    // ここで 'data' は JavaScript オブジェクトです。そのプロパティにアクセスできます。
    console.log("Successfully parsed JSON data:");
    console.log(`Todo Title: ${data.title}`);
    console.log(`Is Completed: ${data.completed}`);
  })
  .catch((error) => {
    // .catch() ブロックは、fetch 操作中にエラーが発生した場合に実行されます。
    console.error("Error fetching or parsing data:", error);
  });

この更新されたコードでは、2 番目の .then() ブロックは data を JavaScript オブジェクトとして受け取ります。テンプレートリテラル(バッククォート ` 構文)を使用して、data.titledata.completed の値を含む文字列を作成し、JSON が正常に解析されたことを示します。

次に、ターミナルでスクリプトを再度実行して、新しい出力を確認します。

node ~/project/index.js

解析された JSON オブジェクトのプロパティに正常にアクセスできたことを確認する、より構造化された出力が表示されます。

期待される出力:

Successfully parsed JSON data:
Todo Title: delectus aut autem
Is Completed: false

取得したデータを HTML 要素に表示する

このステップでは、API からフェッチしたデータを Web ページに表示する方法を学びます。開発中はコンソールにデータをログ出力することが便利ですが、最終的な目標は多くの場合、この情報をユーザーに提示することです。これには、コンテンツを構造化するための HTML ファイルと、Document Object Model (DOM) を操作するための JavaScript が必要です。

まず、HTML ファイルが必要です。左側のファイルエクスプローラーで、~/project ディレクトリに index.html という名前の新しいファイルを作成します。

以下の基本的な HTML 構造を index.html ファイルに追加します。このファイルには見出しと、data-output という ID を持つ div 要素が含まれており、これはフェッチしたデータを格納するコンテナとして機能します。ボディの末尾にある <script> タグは、HTML 要素がロードされた後に JavaScript が実行されることを保証します。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>API Data Display</title>
  </head>
  <body>
    <h1>Fetched Todo Item</h1>
    <div id="data-output">
      <p>Loading data...</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

次に、この HTML と連携するように ~/project/index.js ファイルを変更する必要があります。コンソールへのログ出力の代わりに、スクリプトは ID で div 要素を見つけ、API からのデータでそのコンテンツを更新します。

~/project/index.js の内容を以下のコードに置き換えてください。

const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";

// データを表示する HTML 要素を選択します
const outputElement = document.getElementById("data-output");

fetch(apiUrl)
  .then((response) => response.json())
  .then((data) => {
    // データが取得できたら、HTML コンテンツを更新します。
    // innerHTML を使用して、「Loading...」メッセージを構造化されたデータに置き換えます。
    outputElement.innerHTML = `
      <p><strong>Title:</strong> ${data.title}</p>
      <p><strong>Completed:</strong> ${data.completed}</p>
    `;
  })
  .catch((error) => {
    // エラーが発生した場合は、ユーザーにエラーメッセージを表示します。
    outputElement.textContent = "Failed to load data.";
    console.error("Error fetching data:", error);
  });

結果を確認するには、これらのファイルを Web サーバー経由で提供する必要があります。LabEx 環境には Python が組み込まれており、簡単な組み込み Web サーバーがあります。

  1. WebIDE で新しいターミナルを開きます。
  2. 次のコマンドを実行して Web サーバーを開始します。これにより、現在のディレクトリ (~/project) のファイルがポート 8080 で提供されます。
python3 -m http.server 8080
  1. LabEx プラットフォームは、この実行中のサービスを検出し、「Web 8080」タブを提供して index.html ページをプレビューします。
Web server running in terminal and preview tab

これで、Web ページにフェッチされた「todo」アイテムのタイトルと完了ステータスが表示され、最初の「Loading data...」メッセージが置き換えられているはずです。

API 呼び出しのためのエラーハンドリングを実装する

このステップでは、適切なエラーハンドリングを実装することで、API コールをより堅牢にします。API リクエストは、URL の間違い、ネットワークの問題、サーバー側の問題など、さまざまな理由で失敗する可能性があります。これらの潜在的な障害を適切に処理することは、より良いユーザーエクスペリエンスを提供するために不可欠です。

fetch API の重要な点は、その Promise が 404 (Not Found) や 500 (Internal Server Error) のような HTTP エラー状態では拒否されないことです。リクエストの完了を防ぐネットワーク障害が発生した場合にのみ拒否されます。HTTP エラーを処理するには、成功したレスポンス(ステータスコード 200-299)に対して true となるブール値である response.ok プロパティをチェックする必要があります。

レスポンスステータスをチェックし、潜在的なエラーを処理するために、~/project/index.js を更新しましょう。最初の .then() ブロック内にチェックを追加します。

~/project/index.js ファイルの内容を以下のコードに置き換えてください。

const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
const outputElement = document.getElementById("data-output");

fetch(apiUrl)
  .then((response) => {
    // レスポンスが成功したかどうかを確認します。
    // 'ok' プロパティは、ステータスコードが 200-299 の範囲内であれば true になるブール値です。
    if (!response.ok) {
      // そうでない場合は、エラーをスローします。これは .catch() ブロックで捕捉されます。
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then((data) => {
    outputElement.innerHTML = `
      <p><strong>Title:</strong> ${data.title}</p>
      <p><strong>Completed:</strong> ${data.completed}</p>
    `;
  })
  .catch((error) => {
    // ユーザーフレンドリーなエラーメッセージを HTML 要素に表示します。
    outputElement.textContent = "Failed to load data. Please try again later.";
    // デバッグ目的で、技術的なエラーをコンソールにログ出力します。
    console.error("Error fetching data:", error);
  });

エラーハンドリングを実際に確認するために、意図的に無効な API URL を使用しましょう。~/project/index.jsapiUrl を、存在しないリソースを指すように変更します。これにより、API は 404 Not Found エラーを返します。

index.js ファイルのこの行を変更します。
const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1';

これを次のように変更します。
const apiUrl = 'https://jsonplaceholder.typicode.com/invalid-path/1';

それでは、結果を見てみましょう。前のステップの Python Web サーバーがまだ実行中の場合は、ブラウザのプレビュータブを更新するだけです。停止した場合は、ターミナルから再度開始してください。

python3 -m http.server 8080

次に、プレビューを開きます。データが表示される代わりに、if (!response.ok) チェックが 404 エラーを捕捉したため、ページにエラーメッセージが表示されるはずです。

Web ページでの期待される出力:

Failed to load data. Please try again later.

重要: 次のステップに進む前に、apiUrl を正しいものに戻すことを忘れないでください:https://jsonplaceholder.typicode.com/todos/1

データを送信するための POST リクエストを行う

このステップでは、POST リクエストを使用してサーバーにデータを送信する方法を学びます。これまでは、データをフェッチ(または「GET」)するだけでした。POST リクエストは、指定されたリソースにデータを送信するために使用され、多くの場合、サーバーの状態を変更したり、新しいエントリを作成したりします。

これを行うには、リクエストメソッド、送信するデータを説明するヘッダー、およびリクエストボディ内のデータ自体を含む、追加情報を fetch 関数に提供する必要があります。

まず、フォームを含めるように ~/project/index.html ファイルを更新します。これにより、API に送信できるデータを入力できるようになります。index.html の内容全体を以下のコードに置き換えてください。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>POST Request Example</title>
  </head>
  <body>
    <h1>Create a New Todo Item</h1>
    <form id="add-todo-form">
      <input
        type="text"
        id="todo-title"
        placeholder="Enter a new todo title"
        required
      />
      <button type="submit">Add Todo</button>
    </form>
    <hr />
    <h2>Server Response:</h2>
    <div id="response-output"></div>

    <script src="index.js"></script>
  </body>
</html>

この HTML は、テキスト入力フィールドと送信ボタンを備えたシンプルなフォームと、サーバーのレスポンスを表示するための div を作成します。

次に、フォームの送信を処理し、POST リクエストを実行するために、~/project/index.js のコードを完全に置き換えます。

~/project/index.js の内容を以下のコードに置き換えてください。

// 新しい todo を作成するための API エンドポイント
const apiUrl = "https://jsonplaceholder.typicode.com/todos";

// DOM からフォームとレスポンス出力要素を取得します
const todoForm = document.getElementById("add-todo-form");
const responseOutput = document.getElementById("response-output");

// フォームの submit イベントに対するイベントリスナーを追加します
todoForm.addEventListener("submit", function (event) {
  // デフォルトのフォーム送信動作を防止します
  event.preventDefault();

  // 入力フィールドからタイトルを取得します
  const todoTitle = document.getElementById("todo-title").value;

  // POST リクエストで送信したいデータ
  const newTodo = {
    title: todoTitle,
    completed: false,
    userId: 1
  };

  // fetch リクエストのオプション
  const requestOptions = {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(newTodo)
  };

  // POST リクエストを実行します
  fetch(apiUrl, requestOptions)
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      // API は、新しい 'id' を含む作成されたオブジェクトを返します
      return response.json();
    })
    .then((data) => {
      // サーバーのレスポンスを出力 div に表示します
      responseOutput.innerHTML = `<p>Successfully created todo!</p><pre>${JSON.stringify(data, null, 2)}</pre>`;
    })
    .catch((error) => {
      responseOutput.textContent = "Failed to create todo.";
      console.error("Error:", error);
    });
});

新しい requestOptions オブジェクトの内訳は次のとおりです。

  • method: 'POST': これは fetch に POST リクエストを実行するように指示します。
  • headers: { 'Content-Type': 'application/json' }: このヘッダーは、ボディ内のデータが JSON フォーマットであることをサーバーに通知します。
  • body: JSON.stringify(newTodo): これは送信する実際のデータです。送信前に JSON 文字列に変換する必要があります。

次に、まだ実行されていない場合は Web サーバーを再度起動します。

python3 -m http.server 8080

プレビューを開き、入力フィールドに新しい todo アイテムのタイトルを入力して、「Add Todo」ボタンをクリックします。成功メッセージと、サーバーから返されたデータ(「作成」したアイテムの新しい id を含む)が表示されるはずです。

Example of successful POST request response

API キーでリクエストを認証する

このステップでは、API キーを使用して API リクエストを認証する方法を学びます。多くの API は、ユーザーの識別、データへのアクセス制御、使用状況の追跡のために認証を必要とします。API キーは、API を使用する権限があることを証明するためにリクエストに含める、一意の文字の文字列です。

API キーを送信する方法はいくつかありますが、一般的で安全な方法の 1 つは、リクエストヘッダーに含めることです。通常は Authorization ヘッダーを使用します。

この例では、API キーを必要とする保護されたユーザーデータをフェッチすることをシミュレートします。コードを変更して、"Bearer" トークンを含む Authorization ヘッダーを含めます。これは、認証資格情報を送信するための標準的な方法です。

まず、~/project/index.html ファイルを単純化して、フェッチされたユーザーデータを表示するだけにします。その内容を以下に置き換えてください。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Authenticated API Request</title>
  </head>
  <body>
    <h1>User Profile (Protected)</h1>
    <div id="user-profile">
      <p>Loading user data...</p>
    </div>
    <script src="index.js"></script>
  </body>
</html>

次に、~/project/index.js の内容を以下のコードに置き換えます。このスクリプトは、ユーザーデータをフェッチするための GET リクエストを行い、ヘッダーに偽の API キーを含めます。

// ユーザープロファイル用の API URL を定義します
const apiUrl = "https://jsonplaceholder.typicode.com/users/1";

// 実際のアプリケーションでは、このキーは API プロバイダーから取得します。
const apiKey = "YOUR_SECRET_API_KEY_HERE";

// 出力用の HTML 要素を選択します
const userProfileElement = document.getElementById("user-profile");

// 認証用のヘッダーを含むリクエストオプションオブジェクトを作成します
const requestOptions = {
  method: "GET",
  headers: {
    Authorization: `Bearer ${apiKey}`
  }
};

// 認証された GET リクエストを実行します
fetch(apiUrl, requestOptions)
  .then((response) => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then((data) => {
    // フェッチされたユーザーデータを表示します
    userProfileElement.innerHTML = `
      <p><strong>Name:</strong> ${data.name}</p>
      <p><strong>Email:</strong> ${data.email}</p>
      <p><strong>Website:</strong> ${data.website}</p>
    `;
  })
  .catch((error) => {
    userProfileElement.textContent = "Failed to load user profile.";
    console.error("Error:", error);
  });

このコードでは:

  • プレースホルダーの apiKey を定義します。
  • requestOptions オブジェクトを作成します。
  • headers の中に Authorization キーを追加します。値 Bearer ${apiKey} は一般的な形式で、「Bearer」はトークンタイプで、その後にキー自体が続きます。

注意: 使用している JSONPlaceholder API は公開されており、実際には API キーを必要としません。このヘッダーは単に無視されます。ただし、このコードは、認証を必要とする多くの実際の API で使用する標準的な方法を示しています。

結果を確認するには、Web サーバーがまだ実行されていない場合は起動します。

python3 -m http.server 8080

次に、プレビューを開きます。ページは正常に読み込まれ、ユーザーのプロファイルが表示され、認証された API リクエストが正しく構造化されていることを示します。

まとめ

この実験では、モダンな fetch API を使用して JavaScript で API を呼び出す方法を学びました。公開 API エンドポイントからデータを取得するための基本的な GET リクエストを行うことから始めました。プロミスを使用して fetch の非同期性を処理し、.then() ブロックを連鎖させてレスポンスを処理し、ボディテキストを JSON として解析することを練習しました。主なスキルには、フェッチしたデータを HTML 要素内に動的に表示すること、および潜在的なネットワーク障害を管理するために .catch() ブロックで堅牢なエラー処理を実装することが含まれます。

これらの基本を基に、必要なヘッダーと JSON ペイロードを含む POST リクエストを構築および実行して、サーバーにデータを送信する方法を探りました。最後に、API 通信を保護するための一般的な方法を学びました。これには、保護されたリソースへの正規のアクセス権を取得するために API キーを含めることが含まれます。