この記事は『CRESCO Advent Calendar 2021』 6日目の記事です。

 

みなさま、はじめまして。エクスペリエンスデザインセンター(EXDC)の網野です。

エクスペリエンスデザインセンター(EXDC)はサービスデザイン、UI/UXがメインになりますが、
ここ1年、業務でフロントエンド開発をおこなう機会がありました。

そこで、Web APIとか非同期処理ってよく聞くけどいまいちわからない・・・
async await、Promiseとかソースコードに書いてあるけど、どう使うの・・・?
となっているフロントエンド初心者の方向けにWeb APIの実装方法を説明します。

Web APIとは

まず「API」とは、「プログラム用のインターフェース」のことです。
データフォーマットは「JSON」や「XML」などを用います。
Web APIは「Web上でHTTP通信を用いるAPI」のことを指します。

よく「REST API」などという言葉を見かけると思いますが、「REST」はアーキテクチャスタイルの一種です。
よくある「クライアント/サーバ構成」などもRESTの特徴の一つです。
この記事ではRESTの説明は割愛しますが、理解を深めるとよりAPIの理解も深まりますので、ぜひ勉強してみてください。

さて、Web APIを実装するために、内部でどのようなことが行われているのか理解していきましょう。

Web APIはHTTPを用いるので、クライアントが出したリクエストをサーバで処理してレスポンスを返します。
1つ1つの操作を見ていきましょう。

  1. クライアントがリクエストメッセージを構成する
  2. クライアントがリクエストメッセージを送信する
  3. サーバがリクエストメッセージを受信する
  4. サーバがリクエストメッセージを解析する
  5. 適切なアプリケーションプログラムへ処理を委譲する
    (データベースから最新記事を取得する、など)
  6. アプリケーションプログラムから結果を取得する
  7. レスポンスメッセージを構成する
  8. レスポンスメッセージを送信する
  9. レスポンスメッセージを受信する
  10. レスポンスメッセージを解析する
  11. クライアントの目的を達成するために必要な処理をする
    (正常な場合:最新記事を 表示する、異常な場合:エラーメッセージを表示する、など)

ここでもう一つ理解したい用語が「URI」です。
URIとは、「リソースを統一的に識別するID」のことです。
統一的とは「すべてが同じルールに従っている」という意味です。
クライアントがリクエストメッセージを構築・送信する際に、サーバ側で設定したURIを指定します。
URIを使うことで、Web上に存在するすべてのリソースを識別することができるのです。

Web APIについてざっくりわかってきたところで、続いて、Web API実装で理解が必要な非同期処理について見ていきましょう。

非同期処理

非同期処理とは、「1つ目の処理の完了を待たずに2つ目の処理実行を開始する処理」を指します。
つまり、並行実行されます。
同期処理は1つ目の処理完了後に2つ目の処理を開始します。同期処理との違いは、図で表すと以下のようになります。

同期処理の場合は、「タスクA」の「処理A1」が完了後、「タスクB」の「処理B1」が開始され、「処理B1」が完了したら「タスクA」の「処理A2」が開始します。
しかし、非同期処理の場合は、「タスクA」の「処理A1」開始後、「タスクB」の「処理B1」が開始し、「処理A2」と「処理B2」が並行して実行されています。

では、どのような場合に非同期処理となるのでしょうか?非同期処理は通信が発生する処理で起こります。
例えば、

  • Web API を叩く
  • データベースへクエリを投げる

などが挙げられます。

なぜ上記の処理は非同期で実行されるのでしょうか?

外部との通信は、自分のシステムでコントロールすることができません。
外部の処理が長くなる場合、処理完了を常に待つようにしてしまうと次の処理に進めず止まってしまいます。
その間、図にも記載の通り、ユーザーBの操作を待たせることにもなってしまうので、重い処理や時間のかかる通信中はユーザーに別の操作を許可するために非同期で実行します。

非同期処理のメリットがわかったところで、非同期処理のデメリットを考えてみましょう。

それは、制御が難しいという点です。
後続の処理で非同期処理の結果を使う場合、実行未完了状態で後続の処理に進んでしまいます。
もちろん正常な結果を得られなくなってしまうので、このような事象を防ぐために非同期処理を同期処理のような方式にする必要があります。

そこで、非同期処理の完了を待つ実装するために、async awaitPromiseといったものを使います。

さっそくasync awaitPromiseの書き方を見てみましょう!

【実装方法】async await

非同期処理の実装方法でよく使用されるのが、このasync awaitとPromiseです。
async awaitの方がわかりやすい書き方ができるため、先にasync awaitの書き方を説明します。
まずは簡単なソースコードを見てみましょう。

const asyncAwaitFunc = async () => {
// 非同期処理
await fetch('https://XXXXXXXXXXXXX/XXX/XXX')
.then((responase) => {
// 非同期処理が成功した場合
  console.log('成功 : ' + responase)
})
.catch((error) => {
// 非同期処理が失敗した場合
  console.log('失敗 : ' + error)
})
}
asyncAwaitFunc();

ポイントは2つです。

  • 非同期処理を含む関数やclassにasyncを書く。
  • 実行完了を待ちたい非同期処理の関数にawaitを書く。

「await」は「待つ」という意味なので、awaitは実行完了を待ちたい処理に付けます。
asyncはawaitを含む関数に付ける必要があります。

これだけで非同期処理の実行完了を待つことができます。
とても簡単ですね!

ちなみに、fetch(‘https://XXXXXXXXXXXXX/XXX/XXX’) という仮の非同期処理を書きましたが、このfetchメソッドは、Fetch APIを使用してリクエスト送信する際に使用します。
Fetch APIはHTTP通信を行ってリソースを取得するためのAPIです。
(詳細はこちらをご覧ください。)

また、ソースコードの中でthenメソッドとcatchメソッドを使用していますが、Promiseの中で説明します。

【実装方法】Promise

Promiseはasync awaitよりわかりずらい書き方になりますが、HTTP通信の実装では理解が必要になりますので、覚えておきましょう。

まず、Promiseとは「非同期処理の結果と結果の値を表すオブジェクト」のことです。
つまり、非同期処理の状態をあらわしたオブジェクトです。

Promiseは以下の3つの状態を持ちます。

  • pending : 初期状態。実行中で成功も失敗もしていない状態
  • fulfilled   : 処理が成功した状態
  • rejected  : 処理が失敗した状態

Promiseを使うためには2段階あります。

  1. Promiseを作成する
  2. Promiseを使う

それでは、まずは非同期処理を使用していない、簡単なソースコードを使って見てみましょう。

// 1. Promiseを作成する
const promiseVar = true;
const promiseFunc = new Promise((resolve, reject) => {
if(promiseVar) {
resolve('成功');
} else {
reject('失敗');
}
});
// 2. Promiseを使う
promiseFunc
.then((response) => {
// 処理が成功した場合
console.log(response); // 成功
})
.catch((error) => {
// 処理が失敗した場合
console.log(error); // 失敗
});

1. Promiseを作成するソースコードのポイントは4つです。

  • Promiseオブジェクトをnew演算子を使ってインスタンス化する
  • Promiseの引数に2つのコールバック関数resolve, rejectを入れる
  • 処理が成功した場合、resolveメソッドが呼ばれる
  • 処理が失敗した場合、rejectメソッドが呼ばれる

2. Promiseを使うソースコードのポイントは2つです。

  • 処理が成功した場合(今回だとpromiseVar = trueの場合)、resolveの値が返される(コンソールログに成功と表示される)
  • 処理が失敗した場合(今回だとpromiseVar = falseの場合)、resolveの値が返される(コンソールログに失敗と表示される)

さきほどPromiseオブジェクトは3つの状態を持つといいましたが、

  • resolve() が呼ばれる → fulfilledの状態(処理が成功した状態)
  • reject() が呼ばれる → rejectedの状態(処理が失敗した状態)

になります。

そして、thenメソッドcatchメソッドですが、これはPromiseオブジェクトのメソッドになります。
Promiseオブジェクトを返すFetch APIでは、thenメソッドやcatchメソッドで結果を受け取れるようにする必要があります。

今度は非同期処理を使用した書き方を見てみましょう。

// 1. Promiseを作成する
const promiseAsynchronousFunc = fetch('https://XXXXXXXXXXXXX/XXX/XXX');
// 2. Promiseを使う
promiseAsynchronousFunc
.then((response) => {
// 非同期処理が成功した場合
console.log(response);
});
.catch((error) => {
// 非同期処理が失敗した場合
console.log(error);
})

先ほどと違い、new Promise … などの記述がありません。

async awaitの説明で出てきたFetch APIはPromiseオブジェクトを返します
そのため、1. Promiseを作成するのは fetch(‘https://XXXXXXXXXXXXX/XXX/XXX’) の部分でできていることになります。

テスト用API無料サービス:JSONPlaceholder

JSONPlaceholderは、REST APIの動作確認を無料でおこなえるオンラインサービスです。
API連携となると、データを用意したりと準備に時間がかかりそうですが、
JSONPlaceholderを使えばAPIの勉強や動作確認をする際に手軽に無料で利用できるので、便利です。

ご自身で勉強したりテストする際にはぜひこちらを利用してみてください。

最後に

最後まで読んでいただき、ありがとうございます。
Web API について、少しは理解が深まりましたでしょうか。
フロントエンドはトレンドの移り変わりが早いのでキャッチアップが大変なところもありますが、
まずは基礎を固めて楽しみながら勉強していけたらと思っています。

下記に記載の参考文献も見ていただくと、理解がより深まると思いますので是非ご覧ください。
書籍や公式サイトでしっかり理解することも大切ですが、
ざっくりと概要を知りたい場合はYouTubeなどの動画で勉強するのも良いと思います。