🦒

Axiosによるエラーハンドリング:404エラー発生時のリカバリー方法

2024/04/27に公開

はじめに

個人開発でWebAPIを叩いときに404エラーが出てしまってAPIの処理が停止してしまいました。
その解決方法をまとめます。

問題が発生した実装

以下のAPIリクエストはメトロポリタン美術館のものになります。
departmentIdはメトロポリタン美術館にある作品の部門(ヨーロッパ絵画やアジアなど)を指定するときに使うものです。
今回はdeparmentId=11で指定しています。

今回のAPI処理を簡単に書くと、

  1. 指定した部門に所蔵されてる作品のidを取得する:getCollectionIds()
  2. 作品ごとにAPIを叩いて、作品個別の情報を取得する:getObject()

の2点になります。

以下実際のコード

// 指定した部門に属している作品のidを入れる
const [collections, setCollections] = useState({id: []})
// 作品個別の情報を入れる
const [object, setObject] = useState([])

const getCollectionIds = () => {
  axios
    .get(
      `https://collectionapi.metmuseum.org/public/collection/v1/search?departmentId=11`
     )
      .then((res) => {
        const newCollection = {
          id: res.data.objectIDs,
        }
        setCollections(newCollection)
      })
      .catch((error) => {
        console.log('Error fetching data:', error)
      })
  }

// getCollectionIdsで取得したidを使って作品個別の情報を取得する
const getObject = async () => {
  // 作品個別のAPIリクエスト用のURIを生成
  const getApiUrls = collections.id.map(
    (id) => `https://collectionapi.metmuseum.org/public/collection/v1/objects/${id}`
  )
  const requests = getApiUrls.map((url) => axios.get(url))
  const responses = await Promise.all(requests)
  const data = responses.map((res) => res.data)
  setObject(data)
}

この実装方法で試してみると問題が発生しました。

getCollectionIds()で取得したものの中にデータを持たないものがありました。

{
"message": "Not a valid object"
}

リクエストした先のデータが空だったため404エラーが返ってきて処理が止まってしまいました。

AxiosError {message: 'Request failed with status code 404', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}

エラーハンドリングでデータが空だった時の処理を実装する

404が返ってきたときに処理を止まるのではなく、データが空だったら次の処理に進むようにします。
今回はtry/catchを使って処理します。

const [collections, setCollections] = useState({id: []})
const [object, setObject] = useState([])

const getObjectIDs = (departmentId) => {
  // 略
}

const getObject = async () => {
  const getApiUrls = collections.id.map(
   (id) => `https://collectionapi.metmuseum.org/public/collection/v1/objects/${id}`
  )
 // 404が返ってきた時の処理をする
  try {
    const requests = getApiUrls.map((url) =>
      axios.get(url).catch((error) => {
    // データが空だったときはnullを返す
        if (error.response?.status === 404) {
          console.log(`IDが見つかりませんでした: ${url}`)
     return null
    }
     throw error
    })
  )
    const responses = await Promise.all(requests)
        // フィルターをかけてnullのデータを取り除く
    const data = responses.filter((res) => res !== null).map((res) => res.data)
    setObject(data)
  } catch (error) {
    console.error('Error fetching object data:', error)
  }
}

上記のようにエラーハンドリングを書くことで最後まで処理をしてくれます。

Discussion