NuxtでAxiosを使い始める
公開: 2022-03-10ayncData
メソッドとfetch
メソッドを使用して、Axiosを使用してサーバー側でデータをフェッチする方法と、2つのメソッドの違いについても学習します。 最後に、Authモジュールを使用してアプリケーションに認証を追加する方法を学習します。Nuxt.jsは、アプリケーションと簡単に統合できるAxiosモジュールを提供します。 Axiosは、ブラウザとNode.js環境で動作するPromiseベースのHTTPクライアントです。簡単に言うと、クライアント側のアプリケーションとNode.js環境でリクエスト(API呼び出しなど)を行うためのツールです。
このチュートリアルでは、Axiosモジュールの使用方法と、asyncDataとfetchを使用してサーバー側でリクエストを行う方法を学習します。 これらの2つのメソッドはサーバー側でリクエストを行いますが、いくつかの違いがあり、これについても説明します。 最後に、認証モジュールと認証ミドルウェアを使用して認証を実行し、ページ/ルートを保護する方法を学習します。
この記事では、その上に構築するため、NuxtjsとVuejsの基本的な知識が必要です。 Vuejsの経験がない方は、この記事を続ける前に、公式ドキュメントとNuxt公式ページから始めることをお勧めします。
Nuxt.js Axiosモジュールとは何ですか?
公式ドキュメントによると、
「これは、Nuxt.jsとの安全で簡単なAxios統合です。」
その機能の一部を次に示します。
- クライアント側とサーバー側のベースURLを自動的に設定します。
- SSRのプロキシ要求ヘッダー(認証に役立ちます)。
- フェッチスタイルのリクエスト。
- リクエストを行う際にNuxt.jsプログレスバーと統合されます。
アプリケーションでaxiosモジュールを使用するには、最初にnpm
またはyarn
を使用してモジュールをインストールする必要があります。
糸
yarn add @nuxtjs/axios
NPM
npm install @nuxtjs/axios
それをnuxt.config.js
ファイルに追加します。
modules: [ '@nuxtjs/axios', ], axios: { // extra config eg // BaseURL: 'https://link-to-API' }
modules
配列は、dotenv、auth、この場合はAxiosなどのNuxt.jsモジュールのリストを受け入れます。 私たちが行ったことは、 @nuxtjs/axios
を使用して参照するAxiosモジュールを使用することをアプリケーションに通知することです。 次に、クライアント側とサーバー側の両方のbaseURLなどの構成のオブジェクトであるaxios
プロパティが続きます。
これで、 this.$axios.method
またはthis.$axios.$method
$ axios。$ methodを呼び出すことにより、アプリケーションのどこからでもAxiosにアクセスできます。 メソッドは、 get
、 post
、またはdelete
のいずれかになります。
Axiosを使用して最初のリクエストを行う
このチュートリアルでは、Githubに簡単なアプリケーションをまとめました。 リポジトリには、startとfinishの2つのフォルダーが含まれ、 startフォルダーには、チュートリアルを開始するために必要なすべてのものが含まれています。 フィニッシュフォルダーには、作成するものの完成バージョンが含まれています。
リポジトリのクローンを作成してstart
フォルダーを開いた後、 package.json
ファイルにすべてのパッケージをインストールする必要があるため、ターミナルを開いて次のコマンドを実行します。
npm install
それが完了したら、 npm run dev
コマンドを使用してアプリを起動できます。 これは、 localhost:3000
に移動したときに表示されるはずです。
次に行う必要があるのは、アプリケーションのルートフォルダーに.env
ファイルを作成し、それにAPIURLを追加することです。 このチュートリアルでは、ユーザーからレポートを収集するために構築されたサンプルAPIを使用します。
API_URL=https://ireporter-endpoint.herokuapp.com/api/v2/
このように、APIをアプリにハードコーディングする必要はありません。これは、2つのAPI(開発と本番)での作業に役立ちます。
次のステップは、 nuxt.config.js
ファイルを開き、上記で追加したaxios構成に環境変数を追加することです。
/* ** Axios module configuration */ axios: { // See https://github.com/nuxt-community/axios-module#options baseURL: process.env.API_URL, },
ここでは、このAxiosモジュールを使用するたびに、クライアント側とサーバー側の両方のリクエストにこのbaseURL
を使用するようにNuxt.jsに指示します。
次に、レポートのリストを取得するために、 index.vue
ファイルを開き、次のメソッドをスクリプトセクションに追加します。
async getIncidents() { let res = await this.$store.dispatch("getIncidents"); this.incidents = res.data.data.incidents; }
私たちが行ったことは、 getIncidents()
を呼び出す非同期関数を作成することであり、名前からそれが何をするかを知ることができます—Vuexストアアクションメソッドthis.$store.dispatch
を使用してインシデントのリストをフェッチします。 このアクションからの応答をインシデントプロパティに割り当てて、コンポーネントで使用できるようにします。
コンポーネントがマウントされるたびにgetIncidents()
メソッドを呼び出したいと思います。 mounted
たフックを使用してそれを行うことができます。
mounted() { this.getIncidents() }
mounted()
は、コンポーネントのマウント時に呼び出されるライフサイクルフックです。 これにより、コンポーネントがマウントされたときにAPIが呼び出されます。 次に、ストアのindex.js
ファイルに移動して、Axiosリクエストを作成するこのアクションを作成します。
export const actions = { async getIncidents() { let res = await this.$axios.get('/incidents') return res; } }
ここでは、非同期関数であるgetIncidents
というアクションを作成し、サーバーからの応答を待って、この応答を返します。 このアクションからの応答は、 index.vue
ファイルのgetIncidents()
メソッドに返送されます。
アプリケーションを更新すると、ページにレンダリングされたインシデントの長いリストを表示できるようになります。
Axiosを使用して最初のリクエストを行いましたが、それだけではありませんasyncData
とfetch
を試して、それらの違いを確認し、Axiosを使用します。
AsyncData
AsyncDataはサーバー側でデータをフェッチし、ページコンポーネントをロードする前に呼び出されます。 ページコンポーネントデータが作成される前に呼び出されるため、 this
にはアクセスできません。 this
は、 created
フックが呼び出された後にのみ使用できるため、Nuxt.jsは返されたデータをコンポーネントのデータに自動的にマージします。
asyncData
を使用すると、サーバー側でサイトのコンテンツを取得し、コンテンツの読み込みを高速化できるため、SEOに適しています。 asyncData
メソッドは、コンポーネントフォルダーでは機能しないため、アプリケーションのページフォルダーでのみ使用できることに注意してください。 これは、コンポーネントが作成される前にasyncData
フックが呼び出されるためです。
index.vue
ファイルにasyncData
を追加して、インシデントデータの読み込み速度を観察してみましょう。 コンポーネントプロパティの後に次のコードを追加し、マウントされたフックを削除します。
async asyncData({ $axios }) { let { data } = await $axios.get("/incidents"); return { incidents: data.data.incidents }; }, // mounted() { // this.getIncidents(); // },
ここで、 asyncData
メソッドはコンテキスト$axios
axiosからプロパティを受け入れます。 このプロパティを使用してインシデントのリストを取得すると、値が返されます。 この値は、コンポーネントに自動的に挿入されます。 これで、ページを更新し、レンダリングするインシデントが発生しない場合に、コンテンツの読み込み速度を確認できます。
フェッチ
Fetchメソッドは、サーバー側でリクエストを行うためにも使用されます。 ライフサイクルで作成されたフックの後に呼び出されます。つまり、コンポーネントのデータにアクセスできます。 asyncData
メソッドとは異なり、fetchメソッドはすべての.vueファイルで使用でき、 Vuexストアで使用できます。 これは、データ関数に次のものがある場合を意味します。
data() { return { incidents: [], id: 5, gender: 'male' }; }
this.id
またはthis.gender
を呼び出すことで、 idまたはgenderを簡単に変更できます。
プラグインとしてのAxiosの使用
Axiosを使用した開発の過程で、アプリケーションが意図したとおりに機能するように、リクエストのインスタンスやインターセプターを作成するなどの追加の構成が必要になる場合があります。ありがたいことに、Axiosをプラグインに拡張することでそれを実現できます。
axios
を拡張するには、 plugins
フォルダーにプラグイン( axios.jsなど)を作成する必要があります。
export default function ({ $axios, store, redirect }) { $axios.onError(error => { if (error.response && error.response.status === 500) { redirect('/login') } }) $axios.interceptors.response.use( response => { if (response.status === 200) { if (response.request.responseURL && response.request.responseURL.includes('login')) { store.dispatch("setUser", response); } } return response } ) }
これは私がNuxtアプリケーション用に書いたプラグインの例です。 ここで、関数は$axios
のコンテキストオブジェクトを受け取り、プラグインの構成に使用するstore
とredirect
を行います。 最初に行うことは、 $axios.onError
を使用してステータス500
のエラーをリッスンし、ユーザーをログインページにリダイレクトすることです。
また、アプリケーションで行うすべての要求応答をインターセプトするインターセプターがあり、取得した応答のステータスが200
であるかどうかを確認します。 それが当てはまる場合は、先に進み、 response.request.responseURL
があり、ログインが含まれているかどうかを確認します。 これがtrueであることが確認された場合、ストアのディスパッチメソッドを使用してこの応答を送信し、状態を変更します。
このプラグインをnuxt.config.js
ファイルに追加します。
plugins: [ '~/plugins/axios' ]
これを行った後、Axiosプラグインは、ユーザーが行ったリクエストをインターセプトし、特別なケースを定義したかどうかを確認します。
Authモジュールの概要
authモジュールは、Nuxtアプリケーションの認証を実行するために使用され、 $this.auth
を使用してアプリケーションのどこからでもアクセスできます。 また、 $auth
として、コンテキストオブジェクトからfetch
、 asyncData
、 middleware
、およびNuxtInitServer
で使用できます。
context
は、NuxtからVueコンポーネントまでの追加のオブジェクト/パラメーターを提供し、上記のような特別なnuxtライフサイクル領域で利用できます。
アプリケーションでauthモジュールを使用するには、 yarn
またはnpm
を使用してインストールする必要があります。
糸
yarn add @nuxtjs/auth
NPM
npm install @nuxtjs/auth
それをnuxt.config.js
ファイルに追加します。
modules: [ '@nuxtjs/auth' ], auth: { // Options }
authプロパティは、 strategies
やredirect
などのプロパティのリストを受け入れます。 ここで、 strategies
は次のような好みの認証方法を受け入れます。
-
local
ユーザー名/電子メールおよびパスワードベースのフローの場合。 -
facebook
認証の手段としてFacebookアカウントを使用するため。 -
Github
Githubアカウントでユーザーを認証するため。 -
Google
Googleアカウントでユーザーを認証するため。 - Auth0
- Laravelパスポート
リダイレクトプロパティは、次のリンクのオブジェクトを受け入れます。
-
login
ログインが必要な場合、ユーザーはこのリンクにリダイレクトされます。 -
logout
ログアウト後に現在のルートが保護されている場合、ユーザーはここにリダイレクトされます。 -
home
ログイン後、ユーザーはここにリダイレクトされます。
ここで、 nuxt.config.js
ファイルに以下を追加しましょう。
/* ** Auth module configuration */ auth: { redirect: { login: '/login', logout: '/', home: '/my-reports' }, strategies: { local: { endpoints: { login: { url: "/user/login", method: "post", propertyName: "data.token", }, logout: false, user: false, }, tokenType: '', tokenName: 'x-auth', autoFetchUser: false }, }, }
上記のオプションでuser
エンドポイントが提供されている場合、 auth
メソッドが最適に機能することに注意してください。
auth
configオブジェクト内には、ログインルートを/login
に、ログアウトルートを/
に、ホームルートを/my-reports
に設定するredirect
オプションがあり、これらはすべて期待どおりに動作します。 また、AxiosリクエストのヘッダーにAuthorizationタイプを表すtokenType
プロパティもあります。 デフォルトではBearer
に設定されており、APIで動作するように変更できます。
APIにはトークンタイプがないため、空の文字列のままにしておきます。 tokenName
は、Axiosリクエストのヘッダー内の承認名(またはトークンを添付するヘッダープロパティ)を表します。
デフォルトではAuthorization
に設定されていますが、APIの場合、承認名はx-auth
です。 autoFetchUser
プロパティは、ログイン後にuser
エンドポイントプロパティを使用してユーザーフェッチオブジェクトを有効にするために使用されます。 デフォルトではtrue
ですが、APIにはuser
エンドポイントがないため、 false
に設定しました。
このチュートリアルでは、ローカル戦略を使用します。 私たちの戦略では、ログイン、ユーザー、ログアウトのエンドポイントを持つローカルオプションがありますが、この場合、デモAPIには*logout*
エンドポイントがなく、ユーザーオブジェクトが返されるため、 *login*
オプションのみを使用します。 *login*
が成功したとき。
注: auth
モジュールにはエンドポイントの登録オプションがないため、従来の方法で登録し、 this.$auth.loginWith
を使用して認証を実行するログインページにユーザーをリダイレクトします。 これは、ユーザーの認証に使用される方法です。 最初の引数として「戦略」(例: local
)を受け入れ、次にこの認証を実行するオブジェクトを受け入れます。 次の例を見てください。
let data { email: '[email protected]', password: '123456' } this.$auth.loginWith('local', { data })
認証モジュールの使用
認証モジュールを構成したので、登録ページに進むことができます。 /register
ページにアクセスすると、登録フォームが表示されます。
次のコードを追加して、このフォームを機能させましょう。
methods: { async registerUser() { this.loading = true; let data = this.register; try { await this.$axios.post("/user/create", data); this.$router.push("/login"); this.loading = false; this.$notify({ group: "success", title: "Success!", text: "Account created successfully" }); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } }
ここでは、 registerUser
という非同期関数があります。これは、テンプレートのクリックイベントに関連付けられており、エンドポイント/user/create
に対してtry / catchブロックでラップされたAxiosリクエストを作成します。 これにより、 /login
ページにリダイレクトされ、登録が成功したことがユーザーに通知されます。 リクエストが成功しなかった場合にエラーをユーザーに警告するcatchブロックもあります。
登録が成功すると、ログインページにリダイレクトされます。
ここでは、認証認証メソッドthis.$auth.loginWith('local', loginData)
を使用します。その後、 this.$auth.setUser(userObj)
を使用して、 auth
インスタンスにユーザーを設定します。
ログインページを機能させるために、 login.vue
ファイルに次のコードを追加しましょう。
methods: { async logIn() { let data = this.login; this.loading = true; try { let res = await this.$auth.loginWith("local", { data }); this.loading = false; let user = res.data.data.user; this.$auth.setUser(user); this.$notify({ group: "success", title: "Success!", text: "Welcome!" }); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } }
authメソッドthis.$auth.loginWith('local, loginData)
を使用してlogIn
という非同期関数を作成しました。 このログイン試行が成功した場合は、 this.$auth.setUser(userInfo)
を使用してユーザーデータを認証インスタンスに割り当て、ユーザーを/my-report
ページにリダイレクトします。
this。$ auth.userを使用して、またはthis.$auth.user
this.$store.state.auth.user
使用してVuexでユーザーデータを取得できるようになりましたが、それだけではありません。 auth
インスタンスには、ログインするか、Vue開発ツールを使用して状態を確認するかどうかを確認できる他のプロパティがいくつか含まれています。
this.$store.state.auth
をコンソールに記録すると、次のように表示されます。
{ "auth": { "user": { "id": "d7a5efdf-0c29-48aa-9255-be818301d602", "email": "[email protected]", "lastName": "Xo", "firstName": "Tm", "othernames": null, "isAdmin": false, "phoneNumber": null, "username": null }, "loggedIn": true, "strategy": "local", "busy": false } }
auth
インスタンスには、アプリケーションのnav / headerセクションで認証されたリンクを切り替えるのに役立つloggedIn
プロパティが含まれています。 また、インスタンスが実行しているストラテジーのタイプ(ローカルなど)を示すストラテジーメソッドも含まれています。
次に、このloggedIn
プロパティを使用して、 nav
リンクを配置します。 navBar
コンポーネントを次のように更新します。
<template> <header class="header"> <div class="logo"> <nuxt-link to="/"> <Logo /> </nuxt-link> </div> <nav class="nav"> <div class="nav__user" v-if="auth.loggedIn"> <p>{{ auth.user.email }}</p> <button class="nav__link nav__link--long"> <nuxt-link to="/report-incident">Report incident</nuxt-link> </button> <button class="nav__link nav__link--long"> <nuxt-link to="/my-reports">My Reports</nuxt-link> </button> <button class="nav__link" @click.prevent="logOut">Log out</button> </div> <button class="nav__link" v-if="!auth.loggedIn"> <nuxt-link to="/login">Login</nuxt-link> </button> <button class="nav__link" v-if="!auth.loggedIn"> <nuxt-link to="/register">Register</nuxt-link> </button> </nav> </header> </template> <script> import { mapState } from "vuex"; import Logo from "@/components/Logo"; export default { name: "nav-bar", data() { return {}; }, computed: { ...mapState(["auth"]) }, methods: { logOut() { this.$store.dispatch("logOut"); this.$router.push("/login"); } }, components: { Logo } }; </script> <style></style>
テンプレートセクションには、認証ステータスに応じて適切なリンクを表示するためにauth.loggedIn
を使用しているアプリケーションのさまざまな部分へのリンクがいくつかあります。 logOut()
関数がアタッチされたclick
イベントがあるログアウトボタンがあります。 また、状態認証をnavコンポーネントの計算されたプロパティにマップするmapState
メソッドを使用して、Vuexストアからアクセスされるauthプロパティから取得したユーザーの電子メールを表示します。 VuexアクションlogOut
を呼び出し、ユーザーをlogin
ページにリダイレクトするlogout
メソッドもあります。
それでは、先に進んで、 logOut
アクションを持つようにストアを更新しましょう。
export const actions = { // .... logOut() { this.$auth.logout(); } }
logOut
アクションは、auth logout
メソッドを呼び出します。このメソッドは、ユーザーデータをクリアし、 localStorage
からトークンを削除し、 loggedIn
をfalse
に設定します。
/my-reports
やreport-incident
のようなルートはゲストには表示されないはずですが、アプリのこの時点ではそうではありません。 Nuxtには、ルートを保護できるナビゲーションガードはありませんが、認証ミドルウェアがあります。 独自のミドルウェアを自由に作成できるため、希望どおりに機能するように構成できます。
2つの方法で設定できます。
- ルートごと。
-
nuxt.config.js
ファイル内のアプリ全体に対してグローバルに。
router: { middleware: ['auth'] }
このauth
ミドルウェアはauth
インスタンスで動作するため、ミドルウェアフォルダにauth.js
ファイルを作成する必要はありません。
このミドルウェアをmy-reports.vue
ファイルとreport-incident.vue
ファイルに追加しましょう。 各ファイルのスクリプトセクションに次のコード行を追加します。
middleware: 'auth'
これで、アプリケーションは、これらのルートにアクセスしようとしているユーザーのauth.loggedIn
値がtrue
であるかどうかを確認します。 auth configファイルのredirectオプションを使用して、ログインページにリダイレクトします。ログインしていないときに/my-report
またはreport-incident
にアクセスしようとすると、 /login
にリダイレクトされます。
/report-incidents
に移動すると、これが表示されます。
このページはインシデントを追加するためのものですが、ユーザーがフォームを送信しようとしたときにサーバーに電話をかけないため、現在、フォームはサーバーにインシデントを送信しません。 これを解決するために、ユーザーがReportをクリックしたときに呼び出されるreportIncident
メソッドを追加します。 これは、コンポーネントのスクリプトセクションにあります。 このメソッドは、フォームデータをサーバーに送信します。 report-incident.vue
ファイルを次のように更新します。
<template> <section class="report"> <h1 class="report__heading">Report an Incident</h1> <form class="report__form"> <div class="input__container"> <label for="title" class="input__label">Title</label> <input type="text" name="title" v-model="incident.title" class="input__field" required /> </div> <div class="input__container"> <label for="location" class="input__label">Location</label> <input type="text" name="location" v-model="incident.location" required class="input__field" /> </div> <div class="input__container"> <label for="comment" class="input__label">Comment</label> <textarea name="comment" v-model="incident.comment" class="input__area" cols="30" rows="10" required ></textarea> </div> <input type="submit" value="Report" class="input__button" @click.prevent="reportIncident" /> <p class="loading__indicator" v-if="loading">Please wait....</p> </form> </section> </template> <script> export default { name: "report-incident", middleware: "auth", data() { return { loading: false, incident: { type: "red-flag", title: "", location: "", comment: "" } }; }, methods: { async reportIncident() { let data = this.incident; let formData = new FormData(); formData.append("title", data.title); formData.append("type", data.type); formData.append("location", data.location); formData.append("comment", data.comment); this.loading = true; try { let res = await this.$store.dispatch("reportIncident", formData); this.$notify({ group: "success", title: "Success", text: "Incident reported successfully!" }); this.loading = false; this.$router.push("/my-reports"); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } } }; </script> <style> </style>
ここでは、タイトル、場所、コメントの入力フィールドを備えたフォームがあり、 v-model
を使用した双方向のデータバインディングがあります。 クリックイベント付きのsubmit
ボタンもあります。 スクリプトセクションには、フォームで提供されたすべての情報を収集し、FormDataを使用してサーバーに送信されるreportIncident
メソッドがあります。これは、APIが画像とビデオも受け入れるように設計されているためです。
このformData
は、ディスパッチメソッドを使用してVuexアクションに添付されます。リクエストが成功すると、このリクエストが成功したことを通知する通知とともに/my-reports
にリダイレクトされます。それ以外の場合は、エラーメッセージとともにエラーが通知されます。 。
この時点では、ストアにreportIncident
アクションがまだないため、このページで[送信]をクリックしようとすると、ブラウザコンソールでエラーが表示されます。
これを修正するには、 reportIncidentアクションをindex.js
ファイルに追加します。
export const actions = { // ... async reportIncident({}, data) { let res = await this.$axios.post('/incident/create', data) return res; } }
ここには、空のコンテキストオブジェクトとフォームから送信するデータをreportIncident
関数があります。 次に、このデータは、インシデントを作成してreport-incident.vue
ファイルに戻るpost
リクエストに添付されます。
この時点で、フォームを使用してレポートを追加できるようになります。その後、 /my-reports
ページにリダイレクトされます。
このページには、ユーザーが作成したインシデントのリストが表示されますが、現時点では、上記の内容のみが表示されているので、修正してみましょう。
このリストを取得するために、学習したfetch
メソッドを使用します。 my-reports.vue
ファイルを次のように更新します。
<script> import incidentCard from "@/components/incidentCard.vue"; export default { middleware: "auth", name: "my-reports", data() { return { incidents: [] }; }, components: { incidentCard }, async fetch() { let { data } = await this.$axios.get("/user/incidents"); this.incidents = data.data; } }; </script>
ここでは、 fetch
メソッドを使用してユーザー固有のインシデントを取得し、インシデント配列に応答を割り当てます。
インシデントを追加した後でページを更新すると、次のように表示されます。
この時点で、 fetch
メソッドとasyncData
がデータをロードする方法の違いに気付くでしょう。
結論
これまで、Axiosモジュールとそのすべての機能について学習してきました。 また、asyncDataについて、およびそれらの違いにもかかわらず、両方を一緒にフェッチする方法についても学びました。 また、authモジュールを使用してアプリケーションで認証を実行する方法と、authミドルウェアを使用してルートを保護する方法も学習しました。 これまでに取り上げたすべてのことについて詳しく説明している便利なリソースをいくつか紹介します。
- Nuxjsでメタタグを使い始める。
- Nuxtでdotenvモジュールを使用する。
- NuxtアプリでFetchを使用する。
- asyncDataの使用を開始します。
資力
- 「認証モジュール」、NuxtJS.org
- 「Axiosモジュール:はじめに」、NuxtJS.org
-
FormData
、MDNWebドキュメント - 「API:
asyncData
メソッド」、NuxtJS.org - 「Vueインスタンス:ライフサイクル図」、VueJS.org
- 「Nuxt2.12で
fetch
がどのように機能するかを理解する」NuxtJS.org