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のデベロッパーツールのコンソールで確認してみるとわかる。

1.0 == 1はtrue
1.0は1に変換される

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のバックエンドだけこのようなことが発生するのか検証

  1. json-server (Node.js)
  2. express (Node.js)
  3. 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型になります。