こんにちは、@y_temp4です。
Nuxt.js を使っている方であれば、API リクエストのライブラリとして axios-module を利用するケースが多いかと思います。
しかし、以前こちらの発表を聞かせていただいたときに、「あえて axios-module を使わないで axios を使うことにより、コードの可読性を上げ、変更・追加に強くする」といったことを学びました。
axios-moduleに限らず起こりうる問題だがthisやcontextに注入されるという性質上、
共通化や抽象化をする余地が少なく負債として顕在化しやすい
(上記スライド p 15 より抜粋)
置き換えて得られたもの
・ コードの可読性・一貫性が上がった
・ エディタの解析によって生産性が上がった
・ 変更・追加に強くなった
(上記スライド p 26 より抜粋)
このアプローチは非常に良いと感じましたが、同時に自分は考えました。
「axios-module 使った上で共通化を図りたい・・・!」と(よくばり)。
要は、エンドポイントの関数化を行い、そこから呼び出すrequest.get
等の関数が変更に耐えうる設計であれば良さそうなので、元となる axios が axios-module でも良いと考えました。
(一応ここまでして axios-module を利用したい理由を書いておくと、axios-module は README にあるように様々な便利機能が使えるからです。)
とはいえ、これをやろうとすると別ファイルから強引に $axios を利用する必要があるので、若干面倒です。
何か良いアプローチがないか調べた結果、以下の issue にある方法で自分のやりたいことは実現できそうでした。
Can I use axios-module in non-vue files? · Issue #28 · nuxt-community/axios-module
実装
以下、上記 issue を参考に書いたコードです。
import { setClient } from '~/utils/request'
export default ({ $axios }) => {
setClient($axios)
}
let client
export function setClient(newclient) {
client = newclient
}
function get(url, config) {
return client['$get'](url, config)
}
function post(url, data, config) {
return client['$post'](url, data, config)
}
export default {
get,
post
}
実は動作確認をしていないのですが、多分こんな感じで動くと思います(サンプルのコードでは使うメソッドを reqMethods として一覧にしていましたが、そこまでするかは好みの問題かと思います)。
要は Nuxt の context が使える箇所で $axios を抽象化したいレイヤーに無理やりねじ込む感じですね。これなら新しく nuxt-community が xxx-module を出したときにも対応できるでしょう。
また、他の方法としては上記 issue にあるように window.$nuxt.$axios
を使うという方法もあるかもしれません。こちらは window を参照している関係で利用可能な箇所はクライアントサイドのみですが。
さいごに
とはいえ、繰り返しになりますがこれはかなり強引な方法です。より良いアプローチをご存じの方がいらっしゃれば、ぜひコメントで教えて下さい🙏
また、もしこの記事が参考になった方はいいねしていただけますと幸いです😄