SymbolのAPIをキャッシュする

# はじめに

0.9.6.4のテストネットもブロック高が積みあがっていき、データが増えてきました。

それに伴い、APIの応答も遅くなってきました。

なので、キャッシュしてみようということです。

ブロックチェーンなので、過去のデータは（高確率で）不変なので、キャッシュは有効でしょう。

# やっていき

### バージョン

Endpoint Version: v0.9.6
Catapult REST Version: v1.2.0
Catapult Server Version: 0.9.6.4

### エンドポイント毎にキャッシュすべきか考える

凡例
変化：応答データが不変だと嬉しい
頻度：アクセス頻度
速度：応答速度
対象：キャッシュすべきか

※「変化」は間違っている可能性があります。
※「頻度」「速度」は主観です。

|method|path|変化|頻度|速度|対象|コメント|
|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|-|/ws|-|-|-|-|WebSocket|
|GET|/accounts||🟥|🚀|❌||
|POST|/accounts||🟩||❌||
|GET|/accounts/{accountId}||🟥||❌|残高とかあるので|
|GET|/blocks||🟥|🐄|💛|クエリパラメタが複数あるが、遅いので、特定のパラメタに対してキャッシュしたい|
|GET|/blocks/{height}|😀|🟥|🚀|🟢||
|GET|/blocks/{height}/transactions/{hash}/merkle|😀|🟩||🟢||
|GET|/blocks/{height}/statements/{hash}/merkle|😀|🟩||🟢||
|GET|/chain/height||🟥|🚀|❌||
|GET|/chain/score||🟩|🚀|❌||
|GET|/metadata||🟨||❌|クエリパラメタが複数あるので難しい|
|GET|/mosaics/{mosaicId}||🟨||💛|TTLは短く|
|GET|/mosaics||🟨||❌|クエリパラメタが複数あるので難しい|
|POST|/mosaics||🟩||❌|POSTなので|
|GET|/account/{address}/multisig||🟩||💛|TTLは短く|
|GET|/account/{address}/multisig/graph||🟩||💛|TTLは短く|
|GET|/namespaces||🟨||❌|クエリパラメタが複数あるので難しい|
|GET|/namespaces/{namespaceId}||🟨||💛|TTLは短く|
|POST|/namespaces/*||🟩||❌|POSTなので|
|GET|/network|😐|🟩|🚀|🟢||
|GET|/network/fees/rental||🟩|🚀|❌||
|GET|/network/fees/transaction||🟩|🚀|❌||
|GET|/network/properties|😐|🟩|🚀|🟢|ほぼ変わらないので|
|GET|/node/health||🟨|🚀|❌||
|GET|/node/info|😐|🟨|🚀|🟢||
|GET|/node/peers||🟨|🚀|💛|TTLは短く|
|GET|/node/storage||🟥|🐄|💛|TTLは短く|
|GET|/node/time||🟩|🚀|❌||
|GET|/node/server|😐|🟩|🚀|🟢||
|GET|/restrictions/mosaic/{mosaicId}||🟩||💛||
|POST|/restrictions/mosaic/{mosaicId}||🟩||❌|POSTなので|
|GET|/restrictions/mosaic/{mosaicId}/address/{address}||🟩||💛||
|POST|/restrictions/mosaic||🟩||❌|POSTなので|
|GET|/restrictinos/account/{accountId}||🟩||💛||
|POST|/restrictions/account||🟩||❌|POSTなので|
|GET|/statements/transaction||🟩||❌|クエリパラメタが複数あるので無理|
|GET|/statements/resolutions/address||🟩||❌|クエリパラメタが複数あるので無理そう|
|GET|/statements/resolutions/mosaic||🟩||❌|クエリパラメタが複数あるので無理そう|
|PUT|/transactions|-|-|-|-|-|
|GET|/transactions/confirmed||🟥|🐄|💛|クエリパラメタが複数あるが、アクセス頻度が多いので、特定のパラメタに対してキャッシュしたい|
|POST|/transactions/confirmed||🟩||❌|POSTなので|
|GET|/transactions/confirmed/{transactionId}|😀|🟥|🚀|🟢|不変|
|GET|/transactions/unconfirmed||🟨||❌|すぐ変わるので|
|POST|/transactions/unconfirmed||🟩||❌|POSTなので|
|GET|/transactions/unconfirmed/{transctionId}||🟥||❌|すぐ変わるので|
|GET|/transactions/partial||🟨||❌|すぐ変わるので|
|PUT|/transactions/partial|-|-|-|-|-|
|POST|/transactions/partial||🟩||❌|POSTなので|
|GET|/transactions/partial/{transactionId}||🟨||❌|すぐ変わるので|
|PUT|/transactions/cosignature|-|-|-|-|-|
|POST|/transactionStatus||🟩||❌|POSTなので|
|GET|/transactionStatus/{hash}||🟥||❌|confirmedになる前はすぐに変わる可能性がある|

そして、頻度が多くて、変化しないもの。これはキャッシュする。

- /blocks/{height}
- /transactions/confirmed/{transactionId}


リクエスト頻度が多くて、応答が遅いもの。

- /blocks
- /transactions/confirmed

これらはクエリパラメータによっては、応答が変化するのでやっかい。


### `/blocks`の戦略

ブロックエクスプローラーを考えると、こんなURLになると思う。

|URL|説明|
|:--:|:--:|
|/blocks?p=1|最新の100ブロック|
|/blocks?p=2|次の100ブロック|
|/blocks?p=3|その次の100ブロック|
|...|...|

でもこれはすごくキャッシュしにくいので、妥協して、

|URL|説明|
|:--:|:--:|
|/blocks?p={P}|`(P-1)*100 + 1`～最新のブロック|
|...|...|
|/blocks?p={p}|`(p-1)*100 + 1`～`p*100`|
|...|...|
|/blocks?p=6|501～600ブロック|
|/blocks?p=5|401～500ブロック|
|...|...|
|/blocks?p=1|1～100ブロック|

RESTには`/blocks?pageSize=100&order=asc&pageNumber={p}`でアクセスする。

`P`ページ目とか、キャッシュの関係で100ブロックに満たない場合は、`/blocks/{height}`からとってくる。

これはキャッシュが効くから。

`/blocks`ではページネーションの情報も返ってくる（例えば総ページ数）のだが、これは捨てる。

`/chain/height`は早いので、なんとかなると思う。

### `/transactions/confirmed`の戦略

ブロックエクスプローラーを考えると、以下の２種類かなあ。

- 全トランザクション一覧
- 新着トランザクション一覧

#### 全トランザクション一覧

う～ん、ムリそう

#### 新着トランザクション一覧

新しいブロックが生まれたら、そこにあるトランザクション一覧が欲しいので、RESTには`/transactions/confirmed?height=244076&pageSize=100&order=desc&pageNumber=1`とかでアクセスする。

ブロックが承認されたら、トランザクションの数や内容は変化しないので、順序にかかわらずキャッシュできる。

### CloudFront

色々調べましたが、CloudFrontではクエリ文字列の値でキャッシュかスルーかを振り分けることができないようです。

もう全部キャッシュしちゃって、クライアント側でAPIに直アクセスするかCloudFrontにアクセスするかを制御したほうが早い気がします。

### Nuxtクライアント

Axios Moduleを使うならば、このようにしてリクエスト先を複数作ることが簡単にできる。

https://axios.nuxtjs.org/extend#create-new-axios-instance-based-on-defaults

# 感想

キャッシュの勉強になった。

CloudFrontを使うと、httpsプロキシ的なことができるなと思った。