0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

axios を async/await で書き直した時の課題をメモ

Last updated at Posted at 2020-09-09

概要

request が deprecated になっており、トレンドも axios に移っているようだ。

なので、コードの置き換えを検討している。async/await にすると可読性があがるかもと試した内容を記載する。

結論

結論からいうと因果関係のある処理を async/await に置き換えると可読性が高まる。

サンプルコード: then()を使う

ユーザー認証をして得たトークンを元にリクエストをする例。
簡単すぎるコードでは検証にならないのでやや複雑なコードになっている。

'use strict'

const axios = require('axios');

axios(
  {
    url: 'https://httpbin.org/post?token=XXXXXXXX',
//  url: 'https://httpbin.org/status/500?token=XXXXXXXX',
    headers: {
      'Content-Type': 'application/json'
    },
    method: 'post',
    data: {
      id: 'john.doe',
      pass: '********'
    }
  }
).then(function (responseToken) {
  console.log(`Request URI: ${responseToken.config.url}`);
  const token = responseToken.data.args.token;
  console.log(token);
  axios(
    {
      url: 'https://httpbin.org/get?foo=bar',
      headers: {
        'Authorization': 'Bearer ' + token
     },
     method: 'get'
    }
  ).then(function (response) {
    console.log(`Request URI: ${response.config.url}`);
    console.log(`response body: ${JSON.stringify(response.data.args)}`);
  }).catch(function(error) {
    console.log(`Request URI: ${error.config.url}`);
    console.log(`${error.response.status} ${error.response.statusText}`);
    return `${error.response.status} ${error.response.statusText}`
  })
}).catch(function(error) {
  console.log(`Request URI: ${error.config.url}`);
  console.log(`${error.response.status} ${error.response.statusText}`);
  return `${error.response.status} ${error.response.statusText}`
})

正常時の実行結果

Request URI: https://httpbin.org/post?token=XXXXXXXX
XXXXXXXX
Request URI: https://httpbin.org/get?foo=bar
response body: {"foo":"bar"}

異常時の実行結果
入れ子なので token 取得に失敗したら、 /get?foo=bar の処理は実行はしない。期待通りの動作。

Request URI: https://httpbin.org/status/500?token=XXXXXXXX
500 INTERNAL SERVER ERROR

サンプルコード: await/asyncを使う

ちょっとわかりにくいと思うが、await axios() await axios() と同じレベルでコードが並んでいる。
入れ子でないので、前のリクエストの結果に依存する処理が増えても可読性が悪くはならない。

例外は二つのリクエストで共通となる。let token = undefined というように let を使っているのは、catch ブロック中でどこまで進んだのか判断できるようにするため。これで、処理の進み具合によってエラー処理を変えることができるため、前述の then/catch のように細かいエラー処理も可能になる。

'use strict'

const axios = require('axios');

async function main() {
  let token = undefined
  let resOfGetToken = undefined
  let resOfGetFoo = undefined
  try {
    resOfGetToken = await axios(
      {
        url: 'https://httpbin.org/post?token=XXXXXXXX',
        // url: 'https://httpbin.org/status/500?token=XXXXXXXX',
        headers: {
          'Content-Type': 'application/json'
        },
        method: 'post',
        data: {
          id: 'john.doe',
          pass: '********'
        }
      }
    )
    token = resOfGetToken.data.args.token;
    console.log(`Request URI: ${resOfGetToken.config.url}`);
    console.log(`token: ${token}`);
 
    resOfGetFoo = await axios(
      {
        url: 'https://httpbin.org/get?foo=bar',
        headers: {
          'Authorization': 'Bearer ' + token
       },
       method: 'get'
      }
    )    
    console.log(`Request URI: ${resOfGetFoo.config.url}`);
    console.log(`response body: ${JSON.stringify(resOfGetFoo.data.args)}`);

  } catch(error) {
    console.log("error.name=" + error.name);
    console.log("error.toString()=" + error.toString());
    console.log("Error.prototype.toString()=" + Error.prototype.toString())
    if ('isAxiosError' in error) {
      console.log(`Request URI: ${error.request.path}`);
      console.log(`${error.response.status} ${error.response.statusText}`);
    }
  }
}

try {
  main()
} catch(e) {
  console.log(e)
}

正常時の実行結果

Request URI: https://httpbin.org/post?token=XXXXXXXX
token: XXXXXXXX
Request URI: https://httpbin.org/get?foo=bar
response body: {"foo":"bar"}

異常時の実行結果
token 取得に失敗し、後続の処理を中断できている。

error.name=Error
error.toString()=Error: Request failed with status code 500
Error.prototype.toString()=Error
Request URI: /status/500?token=XXXXXXXX
500 INTERNAL SERVER ERROR

サンプルコード3: パラメータを組み立てる処理を関数化した

'use strict'

const axiosBase = require('axios');
const axiosToBFF = axiosBase.create(
  {
    baseURL: 'https://httpbin.org'
  }
)

async function getToken(id_, pass_) {
  return axiosToBFF.request(
    {
      url: '/post?token=XXXXXXXX',
      // url: '/status/500?token=XXXXXXXX',
      headers: {
        'Content-Type': 'application/json'
      },
      method: 'post',
      data: {
        id: id_,
        pass: pass_
      }
    }
  )
}

async function getFoo(val) {
  return axiosToBFF.request(
    {
      url: `/get?foo=${val}`,
      headers: {
        'Accept': 'application/json',
        'Cache-Control': 'no-cache'
      },
      method: 'get'
    }
  )
}

async function main() {
  let accessToken = undefined
  let resOfGetToken = undefined
  let resOfGetFoo = undefined
  try {
    resOfGetToken = await getToken('john.doe', '********')
    accessToken = resOfGetToken.data.args.token;
    console.log(`Request URI: ${resOfGetToken.config.url}`);
    console.log(`token: ${accessToken}`);

    axiosToBFF.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`

    resOfGetFoo = await getFoo("bar") 
    console.log(`Request URI: ${resOfGetFoo.config.url}`);
    console.log(`response body: ${JSON.stringify(resOfGetFoo.data.args)}`);
  } catch(error) {
    console.log("error.name=" + error.name);
    console.log("error.toString()=" + error.toString());
    console.log("Error.prototype.toString()=" + Error.prototype.toString())
    if ('isAxiosError' in error) {
      console.log(`Request URI: ${error.request.path}`);
      console.log(`${error.response.status} ${error.response.statusText}`);
    }
  }
}

try {
  main()
} catch(e) {
  console.log(e)
}

参考

0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?