WEB APIを叩いてみよう

Javascript

こんにちはkazutoです。今回は、JavaScriptでWEB APIを叩いてみましょう。題材として当ブログ「kazugramming」の記事を取得していきます。

WEB APIとは

Web APIについて解説する前にまずは、APIについて解説します。

APIとは、「Application Programming Interface」を略した物です。日本語に直してみると「アプリケーションをプログラミングするためのインターフェース」という意味になります。要するにアプリケーションとプログラムを繋ぐ物です。具体的には、ソフトウェアやアプリケーションなどの一部を外部に向けて公開することにより、第三者が開発したソフトウェアと機能を共有できるようにしてくれるものです。

以上の事を踏まえた状態で、Web APIについて解説していきます。

Web APIとは、Web上に公開されていて、外部から呼び出して利用が可能なAPIです。往来のAPIと比べ、扱うのが簡単で、広く使われています。

以前、「天気予報APIを用いて5日間の天気情報を取得しよう」で天気情報を取得するために活用した、OpenWeatherMapというWebサイトをイメージしてもらうと頭の中に入ってくると思います。

※Interface(インターフェース)とは、一般的には「境界面」や「接点」を意味する英語で、何かと何かの繋ぐ部分の役割を表します。
IT用語としてのInterface(インターフェース)の意味合いは、ハードウェアやソフトウェア、ユーザといった要素が、互いに情報をやり取りする際に接する部分のことを表します。

curlコマンドでwpの記事を取得してみよう

Web APIについての概要を抑えた所で、当ブログ「kazugramming」の記事をWeb APIを叩いて、取得してみましょう。このトピックでは、ターミナル内で、curlコマンドを実行してWeb APIを叩いていきます。

curlコマンドとは、サーバから、もしくはサーバへデータ転送を行うコマンドです。HTTPプロトコルという規約に従いcurlコマンドを実行します。下記のコマンドをターミナルに入力してください。

 curl -X GET 'https://taketon-blog.com/wp-json/wp/v2/posts' | jq

このコマンド入力したら下記の画像の様にJSON形式でレスポンスが返ってきます。

上記の様にJSON形式のデータ構造がレスポンスとして返ってきたらのなら、正しくWEB APIを叩けた事になります。

 -X GET 

-XというオプションでHTTPメソッドの指定をしています。HTTPメソッドとは、クライアントがサーバーとコミニュケーションをとるための方法です。
HTTPメソッドはいくつか種類が存在します。

HTTPメソッド 概要
GET リソースを取得
HEAD リソースのヘッダー取得
POST 子リソースの作成、リソースへのデータ追加
PUT リソースの更新
DELETE リソースの削除
PATCH PUTと同じだが、差分のみを置き換える
OPTIONS リソースがサポートしているメソッドの取得
TRACE プロキシ動作の確認
CONNECT プロキシ動作のトンネル接続への変更
LINK 他の情報との関連付け
UNLIN LINKで設定した関連を外す

全てを覚える必要がありませんが以下の4つは、抑えておきましょう。

  • GET
  • POST
  • PUT
  • DELETE

上記の4つのメソッドは、サーバー通信するときによく使うので覚えておきましょう。この4つのメソッドを使ってサーバ通信を行い、データを

  • CREATE(生成)
    →POSTメソッド
  • READ(参照)
    →GETメソッド
  • UPDATE(更新)
    →PUTメソッド
  • DELETE(削除)
    →DELETEメソッド

をしていきます。この様なデータの管理や操作の事をそれぞれの頭文字をとってCRUD処理と呼びます。

| jq

jqコマンドはターミナル上でjson形式の文字列を整形したり加工したりするコマンドです。jqコマンドを、curlコマンドに付け加えないと以下の様な、整形されていない複雑なデータ構造がレスポンス値として返ってきます。

このデータ構造を見ても、正しいレスポンス値が返ってきているのかは、わかりません。なので、jqコマンドを用いて、JSON形式のデータ構造にパースしてターミナル内に表示しました。

なおjqコマンドは、maxのターミナルにはデフォルトにはありませんので、ご自身で環境構築していただく必要があります。今回は、僕が Homebrewというパッケージ管理ツールを使用している関係上、Homebrewユーザを対象に導入方法を解説します。

下記のコマンドをターミナル で実行してください。

brew install jq

無事、インストールできたら、以下のコマンドを実行してみましょう。

echo '{"blog":{"name":"kazugramming","type":"特化型サイト"}}' |jq

以下の様に表示されるはずです。

{
  "blog": {
    "name": "kazugramming",
    "type": "特化型サイト"
  }
}

以上で、「curlコマンドでwpの記事を取得してみよう」のトピックは終了になります。続いて、Jacascriptを使ってWEB API を叩いていきましょう。

JavaScriptでWEB APIを叩いてみよう

それでは、JavaScriptでWEB APIを叩いてみましょう。

  • XMLHttpRequestでwpの記事を取得してみよう
  • fetch APIでwpの記事を取得してみよう
  • Promiseで非同期処理を制御してみよう
  • aysnc awaitで非同期処理を制御してみよう

XMLHttpRequestオブジェクトを用いてwpの記事を取得してみよう

まず初めにXMLHttpRequestオブジェクトを用いてWEB APIを叩いてみましょう。XMLHttpRequestオブジェクトとは、ブラウザ上でサーバーとHTTP通信を行うためのAPIです。JavaScriptでHTTP通信をするときによく使われてきた、APIになります。

では、実例を通してWEB APIを叩いてみましょう。今回も「curlコマンドでwpの記事を取得してみよう」と同じくkazugrammingの記事を取得してみましょう。

まずは、基本的な構文を確認をしてみましょう。

//インスタンスを生成
const xml =new XMLHttpRequest()
//リクエスト送る事前準備
xml.open(HTTPMETHOD,URL)
//XMLHttpRequestオブジェクトで行われている
//処理の状況の変化を監視
xml.onreadystatechange=call)
//リクエスト
 xml.send()
//レスポンスを取得
xml.onload=call
//エラーが起きた場合
xml.onerror = call
  

構文を確認をした所で実際の処理内容に置き換えていきましょう。

const xml =  new XMLHttpRequest()
xml.open("GET",'https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')
xml.send()
xml.onreadystatechange = function(){
  if(this.readyState == 4 && this.status == 200){
    console.log("無事リクエストが送られました。");
  }
}
xml.onload= ()=>{
  const Datas =  JSON.parse(xml.responseText)
  console.log(Datas)
}
xml.onerror = function(e){
  console.log("エラーです");
};

それでは解説をしていきます。

const xml =  new XMLHttpRequest()

まずはXMLHttpRequestオブジェクトのインスタンスを生成をしてHTTP通信をする準備を行います。

xml.open("GET",'https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')

続いて、openメソッドを用いて、

  • どの方法でHTTP通信をするか?
  • どのサーバーにリクエストするか?

を設定します。

https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts

今回は上記のURLに対してGETメソッドでリクエストするという設定を行いました。

xml.send()

sendメソッドはリクエストを送るメソッドになります。

xml.onreadystatechange = function(){
  if(this.readyState == 4 && this.status == 200){
    console.log("無事リクエストが送られました。");
  }else{
    console.log("エラーが発生しました。")
 }
}

onreadystatechangeイベントは、XMLHttpRequestオブジェクトで行われている処理の状況の変化を監視することができます。readyStateの値が変化したごとにイベントが発火をするので、状況の変化ごとに処理を記述していきます。

readyStateとは、クライアントの状態の変化を0~4の値で表します。

readyState 概要
0 UNSENT(初期状態)
1 OPENED(openメソッド実行)
2 HEADERS_RECEIVED(レスポンスヘッダー受信)
3 LOADING(ローディング中)
4 DONE(リクエスト完了)

statusはHTTPステータスコードを返します。
HTTPステータスコードとは、Webサーバーからのレスポンス結果を表す3桁の数字です。ステータスコード は100番〜500番まで多くの種類がありそれぞれに意味があります。下記の表をご覧ください。

ステータスコード 意味
100番台 処理が継続中
200番台 リクエスト成功
300番台 リクエストの完了に追加処理が必要
400番台 リクエストが不正・失敗
500番台 サーバエラー

今回は大まかな種類別に表にまとめて置いたので、まずは、大枠を抑えましょう。HTTP通信した際にエラーが出た場合、ステータスコードを見てエラーを解決をしていきます。

xml.onerror = function(e){
  console.log("エラーです");
}

onerrorイベントは、エラーが起きたら発火するイベントです。つまり、このイベントが呼ばれたらリクエストに失敗した事になります。具体的には、ステータスコードが400~500番台の時です。

xml.onload= ()=>{
      const Datas = JSON.parse(xml.responseText)
      Datas.forEach((Data,index)=> console.log(Data);
    });

onload イベントを用いて、レスポンス結果を受け取っています。なおリクエストが成功したタイミングでonload イベントが発火します。ステータスコード が200番台の時です。

JSON.parse(xml.responseText)

レスポンス結果をJSON形式にパースをしています。

responseTextはリクエストに対するレスポンスがテキスト形式で入った 値を返すか、リクエストが失敗した場合や、まだ送信されていない場合は null を返します。

パースをする理由はresponseTextをそのまま表示するだけだと、整形されていないデータが返ってきて、レスポンス結果を確認するのが難しいためです。

そのためJSON形式にパースをしています。

上記の様にレスポンス結果が表示されたら、無事、WEB APIを叩けた事になります。XMLHttpRequestオブジェクトでのHTTP通信は要点を抑えるとそこまで難しいくないのでポイントを抑えておきましょう。

fetch APIでwpの記事を取得してみよう

続いて、fetch APIを用いてwpの記事を取得してみましょう。fetch APIとは、ブラウザ上でサーバーとHTTP通信を行うためのAPIです。XMLHttpRequestオブジェクトで行っていた、HTTP通信の処理をシンプルに書けるようになったのが、fetch APIです。要するに、XMLHttpRequestオブジェクトの上位互換みたいなAPIです。より強力で柔軟な操作が可能になります。

まずは構文を確認をしてみましょう。

fetch(URL,OPTION)
  .then(res=>res)
  .cath(res=>res)

fetch APIは、Promiseというオブジェクトを返します。Promiseオブジェクト とは、非同期処理の最終的な完了処理 、

  • 成功したか
  • 失敗したか

の結果の返します。Promiseは概念が少し難しいので、次のトピックで詳しく解説をします。現段階では、fetch APIの返り値はPromiseというオブジェクトを返すと抑えていてください。

.then(ok_callback,ng_callback)

thenメソッドは、Promise が成功または失敗になるまで処理を受け流し、成功時に ok_callback(成功) を、失敗時に ng_callback (失敗)をコールバック関数として呼び出します。要するにPromiseオブジェクトの返り値を受け取り,返します。

なお非同期処理(HTTP通信)失敗時には、thenメソッド以外にも、catchメソッドでエラーハンドリングを行うことができます。

//()=>==onRejected
catch((reason) => {
   // rejection
});)

catchメソッドは、エラーが発生した時にのみonRejectedというコールバック関数を呼び出し、引数にエラーの原因のreasonを受け取ります。
resonを出力する事でエラーハンドリングを行います。

構文を確認した所で、実際の処理内容に置き換えていきましょう。

それでは、解説していきます。

fetch('https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')
    .then(res=>res.json())
    .then(datas=>console.log(datas))
    .chach(e=>alert(e)))
fetch('https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts'

こちらの記述で、リクエストを送っています。第2引数のoptionは、省略していますが、その場合は自動的にGETリクエストになります。
今回は,リソースを取得(wpの記事)することが目的なので、GETリクエストで問題は無いです。

  • POST
  • DELETE
  • PUT

などのHTTP通信を行う場合は、optionを設定する必要があります。

 .then(res=>res.json())
 .then(datas=>console.log(datas))

thenメソッドでPromiseオブジェクトを受け取って、返しています。詳しく挙動を確認していきましょう。

res=>res.json()

json()は、レスポンス値をJSON形式に整形してPromiseを返します。Promiseを返すので非同期処理となるので、json()の返り値を受け取る場合は、thenメソッドでもう一度チェーンを組み直す必要があります。

then(datas=>console.log(datas))

次のthenメソッドで、json()の返り値、JSON形式に整形されたレスポンス値を、(Promiseオブジェクト)を受け取ります。受け取ったデータを見てみましょう。

上記の様にJSON形式でレスポンス値を受け取れたら、fetcha APIでWEB APIを叩く事に成功しました。

トピックの最後で、エラーを起こしてみましょう。

//URLを適当に消しましょう
fetch('https://taket/wp-json/t')
    .then(res=>res.json())
    .then(datas=>console.log(datas))
    .chach(e=>alert(e))
 .chach(e=>alert(e))

alertメソッドを用いてダイアログを出して、エラーハンドリングをしていきます。

画像の様にTypeError: Failed to fetchと表示されたら成功になります。このエラーの意味はfetchリクエストに失敗したという意味になります。

以上で、「fetch APIでwpの記事を取得してみよう」のトピックを終了になります。Promiseオブジェクトが関わってきて、難しい内容でした。次にもう一段階レベルを上げるために、Promiseを使って、非同期処理を制御していきましょう。

Promiseで非同期処理を制御してみよう

それでは、Promiseで非同期処理を制御していきましょう。本格的な実装に入る前に非同期処理についてポイントを抑えておきましょう。非同期処理とは、 順次実行しない処理の事です。プログラムは、上から順に実行されていき、Aという処理が終わるまでBという処理は実行されません。この事を同期処理といいます。一方、非同期処理は、Aという処理を行っている時にBという処理を実行する事ができます。

少し抽象的な解説になってしまったのでコードをみていきましょう。まずは、順次実行される同期処理を確認をしてみましょう。

console.log("プログラム1")
console.log("プログラム2")
console.log("プログラム3")

上記が同期処理になります。コンソールに出力をすると

順次実行されている事がわかります。

続いて非同期処理を確認をしてみましょう。

fetch('https:/aketong.com/kazugramming/wp-json/wp/v2/posts')
  .then(res=>res.json())
  .then(datas=>console.log(datas))
  .catch(e=>alert(e))
console.log("通信が完了しました。")

コンソール結果を確認をしてみましょう。

上記の画像が確認をしてみましょう。「あれ?順番がおかしい」と思いましたか?

同期処理では、上の処理が終わらない限り、下に書かれているソースコードは、読み込まれません。しかし、非同期処理になると上記の様に上の処理を待たず下の処理が実行されます。非同期処理は同時に処理を動かせるというメリットがありますが、この様に扱いづらい一面もあります。

上記の例だとfetch APIでリクエストを送りレスポンスとしてwpの記事を受け取ってから、「通信が完了しました」と出力しないと、ロジック的におかしいです。この様な問題点を解決するには、非同期処理を制御する必要があります。
なお、このトピックでは、Promiseオブジェクトを用いて、非同期処理を制御していきます。

まずは構文を確認をしてみましょう。

new Promise((resovle,reject)=>{
 .then(res=> resovle("非同期処理が成功した処理"))
  reject("非同期処理が失敗した処理")
})

まず、初めにPromiseの仕様を確認をしましょう。Promiseオブジェクトは、自身の状態によって、非同期処理が

  • 待機中なのか
  • 成功したのか
  • 失敗したのか

を判断をしています。

Promise状態 意味
pending 初期状態
fulfiled 処理が完了
rejected 処理が失敗

Promiseの引数の概要は下記の通りです。

引数 概要
resovle 成功した時に呼び出される関数、状態をfultiledに変更
rejected 失敗した時に呼び出される関数、状態をrejectedに変更

したがって、メソッドチェーンが途切れる最後にresovleを呼び出す必要があります。もし呼び出さなかったら、Promiseオブジェクトの状態が初期状態のままで、処理が完了しません。

rejectはエラーが起きる時に関数を呼び出す必要があります。

以上でPromiseの仕様の解説を終了になります。Promiseは奥が深くまだまだ解説できていない部分がありますが、キリが無いので、スキップします。

では、kazugrammingの記事を取得していきましょう。

const getWpArticles = ()=> new Promise((resovle,reject)=>{
  fetch('https://taketonlog.com/kazugramming/wp-json/wp/v2/posts')
    .then(res=>res.json())
    .then(datas=>resovle(datas))
    .catch(e=>reject(e))
})
getWpArticles()
  .then((datas)=>{
    console.log(datas)
    console.log("通信が完了しました.")})
  .catch(e=>alert(e))

では解説していきます。

const getWpArticles = () => new Promise((resovle,reject)=>{
   
})

定数getsWpArticlesにPromise関数を格納しています。この様に返り値として関数を返す関数を関数のカリー化といいます。

fetch('https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')
 .then(res=>res.json())
 .then(datas=>resovle(console.log(datas)))
 .catch(e=>reject(e))

Promiseオブジェクトの中にHTTP通信(非同期)の処理を登録しています。この様に記述する事によりHTTP通信(非同期)を制御する事ができます。

引数 概要
resovle 成功した時に呼び出される関数、状態をfultiledに変更
rejected 失敗した時に呼び出される関数、状態をrejectedに変更

上記の引数が呼び出されるまで、pendingという初期状態を表す値を返します。つまり、Promiseは状態を評価する事で非同期処理を制御しています

  • 成功したのか
  • 失敗したのか

結末にたどり着くまで、処理をコントロールができます。

.then(res=>res.json())
.then(datas=>resovle(datas))

上記の記述は、成功した時の処理内容をthenメソッドでつないでおります。ポイントは、resovleを呼び出している点です。resovleを呼び出す事で成功した処理の結末を表します。要するにPromiseの状態をfultiledに変更しています。これ以降、処理を記述をしても、resovleが呼び出されてしまっているため、反映されません

.catch(e=>reject(e))

上記の記述は、catchメソッドを用いてHTTP通信が失敗したかを評価しています。ポイントは、rejectを呼び出している点です。rejectを呼び出す事で失敗した処理の結末を表します。これ以降、処理を記述をしても、resovleと同様、反映されません

getWpArticles()
 then((datas)=>{
    console.log(datas)
    console.log("通信が完了しました.")
})
  .catch(e=>alert(e))

上記の記述で、Promiseオブジェクトで管理している非同期処理、今回であれば、HTTP通信の結末を受け取っています。

まずは、HTTP通信が成功した場合について確認をしていきましょう。

 .then(datas=>resovle(datas))
 .then((datas)=>{
    console.log(datas)
    console.log("通信が完了しました.")})

HTTP通信が成功した場合は、resovleの返り値を、thenメソッドで受け取ります。今回の場合は、JSON形式のkazugrammingの記事一覧です。

上記の画像をご覧ください。無事、順次実行されている事がわかります。したがって非同期処理を制御ができたという事になります。

次にHTTP処理が失敗した場合について確認をしていきましょう。

//URLを適当に消してください
fetch('https://taketon-blogkazuing/wp-json/wp/v2/posts')
.catch(e=>reject(e))
.catch(e=>alert(e))

HTTP処理が失敗した場合は、rejectの返り値をcatchで受け取ります。今回の場合は、TypeError: Failed to fetchというエラーです。

上記の画像の様にアラートが表示されます。

以上で、「Promiseで非同期処理を制御してみよう」のトピックを終了します。
次にPromiseよりも簡単に非同期処理を制御ができる、async awaitで非同期処理を制御をしていきましょう。

aysnc awaitで非同期処理を制御してみよう

最後にaysnc awaitを用いて非同期処理を制御をしていきましょう。まずは構文を確認をしていきましょう。

aysnc function (){
  await //非同期処理
}

少し構文の解説をしていきます。

aysnc function(){}

関数を定義をする前にasyncという記述があります。この記述は、非同期関数である事を宣言をしています。非同期関数は、他のコードとは別に実行され、結果として暗黙の Promise を返します。
要するに何も記述しなくとも自動的にPromiseを返すという事です。

await //非同期処理

非同期処理にawait と記述をすると、その処理が完了するまで以降の処理は実行されません。つまり、Promiseの状態が

  • fulfiled(成功)
  • rejected(失敗)

に変化するまで、非同期処理以降の処理が止まります。

構文を確認をした所で、実際にaysnc awaitを使って、非同期処理を制御してみましょう。

const getWpArticles = async ()=>{
 const datas  = await fetch('https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')
                        .then(res=>res.json())
                        .then(datas=>datas)
                        .catch(e=>alert(e))
 console.log(datas);
 console.log("通信が完了しました.")
}
getWpArticles()

それでは、解説していきます。

const datas  = await fetch('https://taketon-blog.com/kazugramming/wp-json/wp/v2/posts')
                        .then(res=>res.json())
                        .then(datas=>datas)
                        .catch(e=>alert(e))

await と記述をすると、その処理が完了するまで以降の処理は実行されません。

//成功した時の最後の処理
.then(datas=>datas)

成功した場合は、JSON形式のkazugrammingの記事一覧を返します。await 式の中で、thenメソッドでメソッドチェーン組んだ場合、最後のthenメソッドが、resovleと同等の役割を担います。
なので最後のthenメソッドの返り値が、その非同期処理の返り値になります。

画像に alt 属性が指定されていません。ファイル名: 58c904e374675f98bf8ee1f016b88bb1.png

失敗した場合は、

.catch(e=>alert(e))

catchメソッドのコールバック関数が呼び出されます。
await式の中でcatchメソッドを用いた場合で且つ非同期処理が失敗した場合は、catchメソッドの返り値が、その非同期処理の返り値になります。

今回は、アラートを表示します。

以上で、「aysnc awaitで非同期処理を制御してみよう」のトピックは終了になります。aysnc awaitを用いるとPromiseと比べ直感的に非同期処理を制御する事ができます。

まとめ:WEB APIを叩いてみよう

今回はWEB APIを叩いて、当ブログ「kazugramming」の記事一覧を取得しました。

  • HTTPメソッド
  • HTTPステータスコード
  • curlコマンド
  • XMLHttpRequestオブジェクト
  • fetch API
  • Promiseオブジェクト
  • async await

とかなり多くの用語が出てきました。いきなり全てを覚えるのはしんどいので、徐々に用語の理解度を上げていきましょう。

以上、kazutoでした。