Oracle ACCS の Application Cacheのアクセスに、NPMパッケージ accs-cache-handlerを使ってみた

# Oracle Application Container Cloud (ACCS） の Application Cache
Oracle Application Container Cloud（ACCS）の Application Cacheは、インメモリ・データグリッドのテクノロジーとして利用されてきた Oracle Coherenceをベースに作られています。簡単にサービスが作成でき、クラスタ構成すればスケーラビリティと可用性が実現できます。Oracle Coherenceを使えるのに安いのがメリットです。

Application Cacheは外部から直接アクセスはできず、ACCS上のアプリからアクセスするロジックを実装する必要があります。

で、アクセスするコードを書くことになるのですが...
# マニュアルのサンプル・コードのややこしいところ
おそらくは大抵の開発者が最初に参照するはずのマニュアルのサンプルコードが、挙動を説明するためとはいえ、ややこしい印象を受けます。（以下がマニュアルのNode.jsからApplication Cacheのチュートリアル）
http://www.oracle.com/webfolder/technetwork/tutorials/obe/cloud/apaas/node/node-accs-caching-basic/node-accs-caching-basic.html#section2

##1. Application Cacheへの `POST` が特殊
サンプルコードでは、クライアントからデータ更新のために PUTメソッドを受け取ると、Application Cacheに対しては `POST` を送信（逆に、クライアントから `POST`を受け取ったときは Application Cache には `PUT` を送信）しています。

Application Cacheの場合、POSTメソッドでは X-Methodというヘッダーに Application Cache 固有の処理情報をセット（たとえば replace や putIfAbsent）します。さらに、POSTのときだけ `Content-Type` を `application/octet-stream`にする必要があります。この使い方の説明のために、「`PUT`メソッドを受け取ると、Application Cache には `POST`」といった、わかりにくいサンプルコードになっているように見えます。

- ちなみに`X-Method`でセットできる値については、以下の`POST`部分を参照のこと
    - https://apicatalog.oraclecloud.com/ui/views/apicollection/oracle-public/cache-app/v1

ただ、データ更新で必ず`POST`しなければいけないわけではなく、`PUT`すればデータの新規作成も更新も両方できてしまいます（が、そのはっきりした説明がマニュアルにはない）。

## 2. ローカルでアプリの実行確認できない
サンプルコードでは、外部からはアクセスできない内部的な Application Cacheの URI にアクセスしています。ローカルでは実行できず、必ず ACCSへのデプロイをしてテストをしなければいけなくなります。簡単な挙動はローカルでテストしたほうが効率的なので、この点がちょっと使いにくい部分です。

ちなみに、Javaの場合、ローカルキャッシュがあります。参考記事：「Application Container Cloud Service のキャッシュ機能をローカル環境で開発してみた」https://qiita.com/shinyay/items/c87fe8877de8661bfeb0 )

# accs-cache-handlerの良さ
そんなときに見つけたのが、`accs-cache-handler`という `NPM`パッケージでした。
https://www.npmjs.com/package/accs-cache-handler
https://redthunder.blog/2017/02/20/developing-with-accs-caching-services/


- 簡単に書ける
    - 稼働するURIを意識する必要がなく、キャッシュ名を指定すればよいだけです　
- ローカルで動かせる
    - Application Cacheを使うかどうかは環境変数を見るだけ
        - ローカルで実行する場合、`Internal Caching URL is not set. Falling back on using a local hashmap instead.`といったメッセ―が出て起動します
        - このアプリを ACCS上にデプロイするときにApplication Cacheをバインドすると、自動的にApplication Cache用の環境変数がセットされ、自動的にApplication Cacheを参照するようになります。

データをキャッシュしてレスポンスを高速にしたい、負荷が高いのでスケールアウト構成にしたいといった、もともとの Oracle Coherence の用途だけでなく、お手軽に Application Cacheにアクセスするコードが書け（かつ安価に利用できる）るので、セッション情報を保持したりステートフルなアプリを書きたいという目的にも使えると思います。

# node-rest-client との実装比較

どれだけコードが違うかを比較するため、マニュアルのサンプルで使われている`node-rest-client`と`accs-cache-handler` それぞれで、最初の宣言部分とデータ更新する部分の実装例を書いてみます。どちらも Application Cache に対して`PUT`します。

```node.js:node-rest-client

let CCSHOST = process.env.CACHING_INTERNAL_CACHE_URL;
let baseCCSURL = `http://${CCSHOST}:8080`;
let cacheName = 'testcache';

var Client = require('node-rest-client').Client;
var client = new Client();

exports.insert = function(req, res, next){
    var keyString = req.params.keyString.toString();
    var body = req.body; 

    var args = {
        data: JSON.parse(JSON.stringify(body)),
        headers: {
          "Content-Type" : "application/json",
        }
    };

    client.put(`${baseCCSURL}/ccs/${cacheName}/${keyString}`, args, function(data, response){
       var responseBody = { };

       res.contenttype='application/json';
       res.charSet('utf-8');

       if(response.statusCode == 200 || response.statusCode == 204) {
           console.log('insert %s successfull',keyString);
           responseBody['status'] = 'Successful.';
       } else {
           responseBody['statusCode'] =  response.statusCode;
           responseBody['headers'] = response.headers;
       }
       res.send(JSON.parse(JSON.stringify(responseBody)));
    });
    next();  
}
```

```node.js:accs-cache-handler


let Cache = require('accs-cache-handler');
let cacheName = 'testcache';
let objCache = new Cache(cacheName);

exports.insert = function(req, res, next){
    var keyString = req.params.keyString.toString();
    var body = req.body;

    objCache.put(keyString, body, function(err){
       if(err) {
           console.log(err);
           res.send(500, JSON.parse(JSON.stringify(err)));
       } else {
           res.send(200);
       }
    });
    next();  
}
```