経緯
Laravel + Vue.jsでTwitter APIを扱うWebアプリの開発をしていました。
Twitterのツイート個別のIDは、桁数が大きいため、DBで扱う際にもINTでは収まらないのでBIGINTを使ったりしています。
今回、Vue.jsからaxiosでデータを取得してJSの変数に格納すると、APIが返すIDと変数のオブジェクトが持つIDが一致していないことに気が付きました。
APIの出力
Vue.jsで持つデータ
大きな整数のときの挙動
json-bigintのReadmeに載っていた例と同じような挙動だったので、それに置き換えて示すと以下のようになります。
APIで返したIDの値とVue.jsのオブジェクトが持つIDの値です。
9223372036854775807
9223372036854776000
このように、大きな整数だと小さい位が丸められてしまっていることがわかりました。
あまり追求できてはいないですが、JSON.parse()では桁数の大きい整数はうまくパースできないということです。
そして、axiosはレスポンスデータをオブジェクトにする際に、JSON.parse()を使っているらしい。
BigIntでもJSON.parseのようにパースできるパッケージ「json-bigint」
NPMインストールで導入できます。
$ npm i json-bigint
axiosでjson-bigintのパースを使う
今回、問題となったツイートIDを使う場面は多いので、デフォルトのtransformResponseを設定することにしました。axiosで取得したデータを好きなように整形するオプションです。
この設定はapp.jsに記述しました。
// axios use JSON BIGINT Parser const JSONbig = require('json-bigint'); axios.defaults.transformResponse = [function (data) { return JSONbig.parse(data); }]
個別に設定する場合は、paramsなどのオプションの部分でtransformResponseを設定できます。
axios.get(\"/api/method\", { params: { ... }, transformResponse: [ data => { return JSONbig.parse(data); } ], })
動作確認
簡単にパースされた値を確認してみました。
console.log(this.tweets[0].id) alert(this.tweets[0].id)
コンソールログ
これで見ると、BigNumberとしてオブジェクトのように格納されているようです。
alert()
コンソールログで見るとオブジェクトっぽく見えましたが、普通にthis.tweets[0].idのような形で使って大丈夫そうです。そのため、既にレスポンスデータを使っている箇所の変更は必要なさそうです。
VueのDevTool
一応、VueのDevToolでもオブジェクトのようになっているようです。
おわり
いっそのこと、文字列にしてしまうとかダサいやり方も考えましたが、スマートに対処できたのでよかったです。