目次
1. きっかけ
Node.js(JavaScript言語)を使ってモックサーバーを立ててレビュー評価を返すモックAPIを作ってクライアント(Flutter)で開発したレビュー評価APIを呼び出したが、下記のエラーが発生しました。
flutter: type 'int' is not a subtype of type 'double'
下記はJSON定義
{ "discoveries": [ { "storeName": "テストお店1", "review": "美味しかった。", ..... "rating": 1.0, }, { "storeName": "テストお店2", "review": "また行きたいお店です。", ..... "rating": 1.5, } ] }
int型は使ってないけど?どういうこと?
筆者のモックサーバーは「json-server」というnpmパッケージをローカルで稼働していて定義URLを叩くと該当するJSONを返してくれる便利なモックサーバです。
定義も正しくdouble型(Flutterはdoubleが基本)を使っているのになんでint型エラーが発生してるのか?
curlで直で叩いてみたらなんと
{ "discoveries": [ { "storeName": "テストお店1", "review": "美味しかった。", ..... "rating": 1, }, { "storeName": "テストお店2", "review": "また行きたいお店です。", ..... "rating": 1.5, } ] }
"rating": 1 ← ここが1.0でなく1になっている?!
2. 理由
色々調べてみるとJavascriptは1 === 1.0は等値であることとだからJavascriptサーバーで開発するときは注意が必要のこと。
Chromeのデベロッパーツールのコンソールで確認してみるとわかる。
There is no such thing as an integer in JavaScript. Numbers in JavaScript are "double-precision 64-bit format IEEE 754 values".
Open up your web browser's console and type 1.0. You'll see 1 printed out. All numbers in JavaScript are floating point numbers, so your serializer simply chose to leave off unnecessary precision.
https://stackoverflow.com/questions/16662031/json-stringify-conversion-of-float-to-int
JavaScriptには整数のようなものはありません。 JavaScriptの数値は、「倍精度64ビット形式のIEEE754値」です。 Webブラウザーのコンソールを開き、1.0と入力します。 1つが印刷されます。 JavaScriptの数値はすべて浮動小数点数であるため、シリアライザーは不要な精度を省くことを選択しただけです。
TL;DR
Pythonのjson-serverパッケージを利用すれば上記の問題解決できます。
3. 検証
JavaScriptのバックエンドだけこのようなことが発生するのか検証
- json-server (Node.js)
- express (Node.js)
- json-server (Python)
json-server(Node.js)
JSON定義をシンプルに変更してもう一度検証
JSON定義
"double": [1.0, 1.5, 2.0]
cURLコマンド実行と結果
$ curl http://localhost:3004/double [ 1, 1.5, 2 ]
結果は予想通りに[1, 1.5, 2]になりました。
Express(Node.js)
JavaScriptサーバーだから同じ結果になるはず!!
JavaScript定義
const express = require('express'); const app = express(); app.get('/double', (req, res) => { res.status(200).json([1.0, 1.5, 2.0]); }); const port = Number(process.env.PORT) || 3000; app.listen(port, () => { console.log(`Application started port: ${port}`); });
cURLコマンド実行と結果
$ curl http://localhost:3000/double [1,1.5,2]
まぁ、これも予想通りですね。
json-server (Python)
json-serverのPythonバージョン。こちらも使い勝手がよかったです。
JSON定義(json-serverのNode.js版をそのまま流用)
"double": [1.0, 1.5, 2.0]
cURLコマンド実行と結果
$ curl http://localhost:3001/double [1.0, 1.5, 2.0]
上記の結果を見れば分かるが、ちゃんとJSONで定義した通りに返ってくる
4. 結論
JavaScriptは1と1.0が等値であるためAPIを開発するときは注意が必要です。
この問題はJavaScriptではなくPythonなど他の言語のサーバーを利用すれば回避できます。
根本的な対策にならないが、JavaScript環境で["1.0", "2.0"]このように文字列でクライアントにAPIを返すかjson["rating"].toDouble()のように変換をかませばdouble型になります。