# JavaScript axiosをasync、awaitとtry、catch、finallyで制御する
HTTP通信ライブラリのaxios (opens new window)を使って、
APIをasync、awaitで制御するコードを書いていく。
# webpackでbabel7 + webpack-dev-server + json-serverの環境構築
Promiseやasync、awaitを使うためにBabel7が使える環境をwebpackで構築していく。ローカルサーバーはwebpack-dev-serverを使う。また、APIのモックサーバーのためにjson-serverを使う。
Babel7の設定ファイルはbabel.config.jsを用意し、
webpackの設定ファイルはwebpack.config.jsを用意する。
json-serverが返すモックのJSONはdb.jsonに用意する。
ディレクトリ
.
├── babel.config.js
├── db.json
├── dist
│ └── index.html
├── package-lock.json
├── package.json
├── src
│ └── index.js
└── webpack.config.js
npm-scriptsでwebpack-dev-serverとjson-serverが並列で起動するようにしておく。
json-serverは--watchでモックのJSONを指定する。--portを指定しておくことで明示的にwebpack-dev-serverとポートが被らないようにする。
package.json
{
"scripts": {
"dev": "run-p build mock",
"build": "webpack-dev-server",
"mock": "json-server --watch db.json --port 3001"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/polyfill": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"babel-loader": "^8.0.5",
"json-server": "^0.14.2",
"npm-run-all": "^4.1.5",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}
babel.config.js
module.exports = function (api) {
api.cache(true);
const presets = [
['@babel/preset-env', {
"useBuiltIns": "usage",
}],
];
return {
presets,
};
}
webpack.config.js
const path = require("path");
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.join(__dirname, "dist"),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
},
]
},
devtool: 'inline-source-map',
devServer: {
open: true,
openPage: "index.html",
contentBase: path.join(__dirname, 'dist'),
watchContentBase: true,
port: 3000,
}
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
bundle.js
import '@babel/polyfill';
console.info('hello')
db.jsonのJSONにしたがって、json-serverは自動で以下のAPIを用意する
/posts/
/posts/[id]
db.json
{
"posts": [
{
"id": 1,
"title": "json-server",
"author": "typicode"
}
]
}
以上の設定をしたらnpmコマンドでサーバーの起動確認をおこなう。
npm run dev
ブラウザでを開き3000ポートでindex.htmlにアクセスできることを確認する。

また、3001ポートで/postsにアクセスするとJSONが返ってきている。

これで環境構築の確認ができた。
# axiosをPromiseのthen、catch、finallyで制御
axiosをインストールし、PromiseでHTTPリクエストが成功する場合と、失敗する場合を確認していく。
npm install axios --save
package.json抜粋
"dependencies": {
"axios": "^0.18.0"
}
# HTTPリクエストが成功する場合
axiosでAPIに対してGETする。
/postsへのリクエストは成功するので、catchのコードは実行されず、thenとfinallyのコードが実行される。
index.js
import '@babel/polyfill';
import axios from 'axios';
console.info('ローディング表示開始')
axios
.get('http://localhost:3001/posts')
.then((response)=> {
console.info('成功です',response.data);
})
.catch((error) => {
console.error('失敗です', error);
})
.finally(() => {
console.info('ローディング表示終了');
});
ブラウザのコンソールを確認する。
axios呼び出し前に「ローディング表示開始」」と出力され、APIを呼び出してJSONが取得できており、最後に「ローディング表示終了」が出力されている。

# HTTPリクエストが失敗する場合
APIのURLを存在しないものに変更することで、HTTPリクエストが失敗する場合をみていく。
index.js
.get('http://localhost:3001/xxx')
APIは存在しないため404エラーになる。
HTTPリクエストが成功する場合と同様に、GET前は「ローディング表示開始」と表示される。しかし、thenは通らなくなるため「成功です」と出力されず、catchに書かれている「失敗です」が出力される。そして、HTTPリクエストの成功、失敗に関わらずfinallyが実行される。finallyは必ず実行されるため、API実行前に表示しておいたローディングを非表示にする処理などで使われる。

# axiosをasync、awaitとtry、catch、finallyで制御
さきほどまでのコードをasync、awaitを使って書き換える。
それに伴いエラーのハンドリングもtry、catch、finallyを使うようにする。
axios.getの前にawaitを書いておき、try、catchで囲む。finallyはcatchに連なる形で書く。そして、関数の前にasyncを記載する。
# HTTPリクエストが成功する場合
index.js
import '@babel/polyfill';
import axios from 'axios';
const getPosts = async () => {
console.info('ローディング表示開始')
try {
const response = await axios.get('http://localhost:3001/posts');
console.info('成功です', response.data);
} catch(error) {
console.error('失敗です', error);
} finally {
console.info('ローディング表示終了');
}
};
(async () => {
console.info('API呼び出し前');
await getPosts();
console.info('API呼び出し後');
})();
ブラウザのコンソールで確認すると、非同期でAPIの呼び出しを行うgetPosts関数の処理が終わってから「API呼び出し後」が出力されていることがわかる。
そして、tryとfinallyのコードが実行されている。

# HTTPリクエストが失敗する場合
async、awaitでもAPIのURLを存在しないものに変更することで、HTTPリクエストが失敗する場合をみていく。
const response = await axios.get('http://localhost:3001/xxx');
HTTPリクエストが成功した場合と同様、非同期処理が終わった後に後続の「API呼び出し後」が出力されている。try内のHTTPリクエストが失敗したaxios.get以降の「成功です」は出力されず、
catchとfinallyが実行される。
これでthen、catchで扱っていたときと同様にasync、awaitでもHTTP通信を制御できることがわかった。
