nuxt.svg

【Nuxt 2】axiosによるAPI連携

Nuxt2

axios とは

axios とは、Promise ベースの HTTP クライアントです。 ブラウザ(クライアント)から外部の API にアクセスし、データの取得や更新を行います。

HTTP クライアントには、AjaxFetch APIなどがありますが、Vue.js では axios を利用することが多いです。 また NuxtJS 用にカスタマイズされた axios も提供されているため、こちらを利用することをオススメします。

インストール

基本的には、プロジェクト作成時に axios を含めるかを選択できます。 これを選択している場合は、以降のインストール作業は不要です。

以下のコマンドで axios をインストールします。

$ npm install @nuxt/axios

インストール完了後、nuxt.config.jsmodulesに以下の設定を追記します。

nuxt.config.js
export default {
  modules: ['@nuxtjs/axios']
}

インストール作業はこれで完了です。

今回使用するのは NuxtJS 用にカスタマイズされた axios になります。 通常の axios も使用できるのですが、こちらの方が設定の手間が省けるなどのメリットがあります。

基本操作

メソッド

@nuxtjs/axiosでは、this.$axiosとインスタンスプロパティとして参照できるようになっています。 例えば GET メソッドでデータを取得する場合は以下のようにします。

getData() {
  this.$axios.get('http://localhost:8080/').then(res => {
    //リクエスト成功時
  }).catch(err => {
    //リクエスト失敗時
  })
}

axios は、実行結果として Promise を返します。 Promise について詳しくは説明しませんが、非同期処理のための仕組みとなります。 thenに処理(リクエスト)が成功した後の処理を、catchに処理(リクエスト)が失敗した後の処理を定義します。

引数のreserrは、それぞれレスポンス情報とエラー情報が渡されます。 レスポンス情報は、取得したデータ(res.data)や HTTP ステータス(res.status)などが参照できます。 エラー情報にはレスポンス情報が含まれており、err.responseで参照できます。

その他の HTTP メソッドについても基本的な考え方は同じで、メソッドがget()からpost()put()delete()に代わるだけです。

async/await

例えば 2 回続けて別の API へアクセスしたい場合、次のような記述になります。

getData() {
  this.$axios('http://localhost:8080/A').then(res1 => {
    //...
    this.$axios('http://localhost:8080/B').then(res2 => {
      //...
    }).catch(err2 => {
      //...
    })
  }).catch(err1 => {
    //...
  })
}

これが 3 回、4 回と増えた場合、どんどんとネストが深くなり、可読性の低いコードとなってしまいます。

これを解決するための仕組みがasync/awaitです。 上記の例をasync/awaitで置き換えると以下のようになります。

async getData() {
  const res1 = await this.$axios('http://localhost:8080/A').catch(err => {
    //...
  })
  const res2 = await this.$axios('http://localhost:8080/B').catch(err => {
    //...
  })
}

ポイントは 2 つ。 1 つは Promise の処理を実行するメソッドの前にasyncを付与します。 もう 1 つは、Promise の処理の前にawaitを付与します。 これによって、通常のプログラム同様上から順に処理が実行されます。

async/awaitが付与された Promise の処理は、結果として成功した場合のデータを返します。 axios では、レスポンス情報を返すことになります。

また以下のようにcatcherr.responsereturnすれば、リクエスト成功時は正常なレスポンス情報、 失敗した場合はエラーのレスポンス情報を取得できるようになります。

async getData() {
  const res = await this.$axios('http://localhost:8080/').catch(err => {
    return err.response
  })
}

パラメーターの設定

クエリパラメーター

クエリパラメーターは、paramsオブジェクトを引数として指定することで設定できます。

async getData() {
  const params = {
    id: '0001',
    name: 'Taro',
    age: 24
  }
  const res = this.$axios.get('http://localhost:8080/', { params }).catch(err => {
    return err.response
  })
}
http://localhost:8080/?id=0001&name=Taro&age=24

URL に直接連結することも可能ですが、オススメはしません。

application/json

POST や PUT などでContent-Type: application/jsonとしてパラメーターを送信する場合は、オブジェクトをそのまま引数に指定します。

async postData() {
  const params = {
    id: '0001',
    name: 'Taro',
    age: 24
  }
  const res = this.$axios.post('http://localhost:8080/', params).catch(err => {
    return error.response
  })
}

application/x-www-form-urlencoded

POST や PUT などでContent-Type: application/x-www-form-urlencodedとしてパラメーターを送信する場合は、URLSearchParamsを使用します。

async postData() {
  URLSearchParams params = new URLSearchParams()
  params.append('id', '0001')
  params.append('name', 'Taro')
  params.append('age', 24)

  const res = this.$axios.post('http://localhost:8080/', params).catch(err => {
    return error.response
  })
}

リクエストヘッダーの設定

API の認証・認可には、トークンを用いた方法がよく使用されます。 認証成功時にトークンを発行し、認可時にリクエストヘッダーのAuthorizationにトークンを設定して送信します。

Authorization: Bearer token

これを axios で設定するには以下のようにします。

GET
getData() {
  const token = 'xxxxxxxxxxxxxx'
  const params = {
    id: '0001',
    name: 'Taro',
    age: 24
  }
  const res = this.$axios.get('http://localhost:8080/', {
    params,
    headers: {
      Authorization: `Bearer ${token}`
    }
  }).catch(err => {
    return err.response
  })
}
POST
postData() {
  const token = 'xxxxxxxxxxxxxx'
  const params = {
    id: '0001',
    name: 'Taro',
    age: 24
  }
  const res = this.$axios.post('http://localhost:8080/', params, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  }).catch(err => {
    return err.response
  })
}

baseURL の設定

接続する API が決まっている場合、baseURLを設定することで URL を省略できます。 bsaeURLの設定は、nuxt.config.jsaxiosに設定します。

nuxt.config.js
export default {
  axios: {
    baseURL: 'http://localhost:8080'
  }
}
getData() {
  // http://localhost:8080/sampleへの接続
  const res = this.$axios.get('/sample').catch(err => {
    return err.response
  })
}

プラグインの活用

プラグインについて

プラグインとは、axios などの外部パッケージの設定などを NuxtJS に反映させるためのものです。 以下の形式の js ファイルで作成し、/pluginsフォルダに配備します。

plugin.js
export default function(context) {
  //設定
}

作成したプラグインは、nuxt.config.jspluginsに指定することで読み込みます。

nuxt.config.js
export default {
  plugins: ['~/plugins/plugin']
}

処理の共通化

@nuxtjs/axiosでは、プラグインを用いることで、リクエストやレスポンス時の共通的な処理を定義することができます。 共通的な処理として、「リクエスト時に決まったヘッダー情報を設定する」、「レスポンス時に決まったヘッダー情報を読み取る」などが考えられます。

これらの共通的な処理は、以下のメソッドによって設定できます。

メソッド説明
onRequest(config)リクエスト時
onResponse(response)レスポンス時
onError(err)エラー時(リクエスト、レスポンス共通)
onRequestError(err)リクエストエラー時
onResponseError(err)レスポンスエラー時
plugins/axios.js
export default function({ $axios }) {
  $axios.onRequest(config => {
    //...
  })
  $axios.onResponse(response => {
    //...
  })
  $axios.onError(err => {
    //...
  })
}

作成したプラグインは、必ずnuxt.config.jsで読み込んでください。

nuxt.config.js
export default {
  plugins: ['~/plugins/axios']
}

以下に具体的な設定例を記載しておきます。

トークン設定の共通化

上記で説明したAuthorizationの設定を、毎回設定するのは手間です。 これを以下のように、tokenの設定のみで済むようにプラグインを作成します。

getData() {
  const token = 'xxxxxxxxxxxxxx'
  const params = {
    id: '0001',
    name: 'Taro',
    age: 24
  }
  const res = this.$axios.get('http://localhost:8080/', { params, token }).catch(err => {
    return err.response
  })
}

今回はリクエスト時の設定のため、onRequestに定義します。

axios.js
export default function({ $axios }) {
  $axios.onRequest(config => {
    if (config.token) {
      config.headers.Authorization = `Bearer ${config.token}`
      delete config.token
    }
    return config
  })
}

エラー処理の共通化

以下は、エラーが発生したら必ずエラーページに遷移するように設定した例です。

axios.js
export default function({ $axios, error }) {
  $axios.onError(err => {
    error({
      statusCode: error.response.status,
      message: error.response.message
    })
  })
}

また以下は、エラーのレスポンス情報を返すように設定した例です。

axios.js
export default function({ $axios, error }) {
  $axios.onError(err => {
    return Promise.resolve(err.response)
  })
}

これらの設定によってcatchの処理が不要になります。

async getData() {
  const res = await this.$axios.get('http://localhost:8080')
}

asyncData

以下は、asyncDataでデータを取得する例になります。 asyncDataについては、別の記事で説明しているためここでは割愛します。

Page
export default {
  async asyncData({ $axios }) {
    const res = $axios.get('/sample')
    return {
      user: res.data.user
    }
  }
}

fetch

NuxtJS2.12 以降の仕様についての説明になります。

fetchは、beforeMountの前に実行される処理で、レンダリング前に外部からデータを取得する目的で使用します。 これはすべてのコンポーネントで使用できます。

export default {
  data: () => ({
    user: undefined,
  }),
  async fetch() {
    const res = this.$axios.get('/sample')
    this.user = res.data.user
  },
}

fetchには、以下のプロパティが用意されています。

プロパティ説明
$fetch()関数fetchを再実行する
$fetchState.pendingBooleantrueの場合はfetchが実行中
$fetchState.errorErrorfetchがエラーになった場合のエラー情報
fetchState.timestampInteger最後にfetchしたタイムスタンプ
<template>
  <div>
    <p v-id="$fetchState.pending">Fetching...</p>
    <p v-else-if="$fetchState.error">Fetch Error</p>
    <p v-else>Fetched</p>
    <button @click="$fetch">Refresh</button>
  </div>
</template>

CORS

CORS とは

CORS は、Cross-Origin Resource Sharing の略で、API を利用する場合にはとても重要な仕組みになります。

まず初めにオリジン(Origin)について説明します。 オリジンとは、プロトコル、ホスト、ポート番号のセットのことです。 例えばhttp://localhost:3000であれば、httpがプロトコル、localhostがホスト、3000がポートになります。 この中の 1 つでも違えば、それは別のオリジンとなります。

CORS は、別のオリジンへのアクセスを制限するための仕組みになります。 例えば、http://localhost:3000からhttp://localhost:8080の API にアクセスする場合、 API 側がhttp://localhost:3000からのリクエストを許可していなければ、CORS のエラーとなります。

実際には、オリジンが違えばすべてのリクエストをブロックするというわけではありません。 詳細は割愛しますが、今回のようなブラウザ(axios)からのリクエスト(XMLHttpRequest)は CORS の対象となっているためブロックされます。

プロキシの設定

では、CORS はどのように回避すればよいのでしょうか。

1 つは API 側でオリジンを許可することです。 しかし、自身が作成していない API の設定を変更することは当然できません。

そこでもう 1 つの回避策としてプロキシを利用します。 API へのリクエストがプロキシからになるため、CORS でブロックされなくなります。

axios では、nuxt.config.jsで以下の設定をすることで擬似的なプロキシを利用できます。

nuxt.config.js
export default {
  axios: {
    proxy: true
  },
  proxy: {
    '/api/': {
      target: 'http://localhost:8080',   //APIのURL
      pathRewrite: { '^/api/': '' }
    }
  }
}

API にアクセスする場合は、以下のように URL を設定します。

getData() {
  // http://localhost:8080/sample へのアクセス
  const res = this.$axios.get('/api/sample')
}