【Nuxt 2】axiosによるAPI連携
axios とは
axios とは、Promise ベースの HTTP クライアントです。 ブラウザ(クライアント)から外部の API にアクセスし、データの取得や更新を行います。
HTTP クライアントには、AjaxやFetch APIなどがありますが、Vue.js では axios を利用することが多いです。 また NuxtJS 用にカスタマイズされた axios も提供されているため、こちらを利用することをオススメします。
インストール
基本的には、プロジェクト作成時に axios を含めるかを選択できます。 これを選択している場合は、以降のインストール作業は不要です。
以下のコマンドで axios をインストールします。
$ npm install @nuxt/axios
インストール完了後、nuxt.config.js
のmodules
に以下の設定を追記します。
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
に処理(リクエスト)が失敗した後の処理を定義します。
引数のres
、err
は、それぞれレスポンス情報とエラー情報が渡されます。
レスポンス情報は、取得したデータ(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 では、レスポンス情報を返すことになります。
また以下のようにcatch
でerr.response
をreturn
すれば、リクエスト成功時は正常なレスポンス情報、
失敗した場合はエラーのレスポンス情報を取得できるようになります。
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 で設定するには以下のようにします。
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
})
}
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.js
のaxios
に設定します。
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
フォルダに配備します。
export default function(context) {
//設定
}
作成したプラグインは、nuxt.config.js
のplugins
に指定することで読み込みます。
export default {
plugins: ['~/plugins/plugin']
}
処理の共通化
@nuxtjs/axios
では、プラグインを用いることで、リクエストやレスポンス時の共通的な処理を定義することができます。
共通的な処理として、「リクエスト時に決まったヘッダー情報を設定する」、「レスポンス時に決まったヘッダー情報を読み取る」などが考えられます。
これらの共通的な処理は、以下のメソッドによって設定できます。
メソッド | 説明 |
---|---|
onRequest(config) | リクエスト時 |
onResponse(response) | レスポンス時 |
onError(err) | エラー時(リクエスト、レスポンス共通) |
onRequestError(err) | リクエストエラー時 |
onResponseError(err) | レスポンスエラー時 |
export default function({ $axios }) {
$axios.onRequest(config => {
//...
})
$axios.onResponse(response => {
//...
})
$axios.onError(err => {
//...
})
}
作成したプラグインは、必ず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
に定義します。
export default function({ $axios }) {
$axios.onRequest(config => {
if (config.token) {
config.headers.Authorization = `Bearer ${config.token}`
delete config.token
}
return config
})
}
エラー処理の共通化
以下は、エラーが発生したら必ずエラーページに遷移するように設定した例です。
export default function({ $axios, error }) {
$axios.onError(err => {
error({
statusCode: error.response.status,
message: error.response.message
})
})
}
また以下は、エラーのレスポンス情報を返すように設定した例です。
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
については、別の記事で説明しているためここでは割愛します。
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.pending | Boolean | true の場合はfetch が実行中 |
$fetchState.error | Error | fetch がエラーになった場合のエラー情報 |
fetchState.timestamp | Integer | 最後に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
で以下の設定をすることで擬似的なプロキシを利用できます。
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')
}