そこそこ実用的な翻訳アプリを開発してみる (4) ログサービスの実装

そこそこ実用的な翻訳アプリを開発しましたので、その構成や作り方を記録しておきます。[コード](https://github.com/yamachan/rtk-lt) は MITライセンスですので、参考になるところがあれば部分的にでも使ってみてください。

# 目次

* [(1) 概要編](https://qiita.com/yamachan360/items/5b20e7181d663d70e924)
* [(2) 開発環境の準備](https://qiita.com/yamachan360/items/d5c4fb2e07d3b9693c37)
* [(3) 翻訳サービスの実装](https://qiita.com/yamachan360/items/fa4af5f7b18781e5f283)
* (4) ログサービスの実装 【このページ】
* [(5) フロントエンド側の実装](https://qiita.com/yamachan360/items/de57df20dc7de5665a44)
* [(6) 学習用データの作成](https://qiita.com/yamachan360/items/7de33c30331745b0d591)

# DBにアクセスしよう

## Cloudantサービスの作成と接続

カタログの「データベース」からNoSQL DBである「Cloudant」サービスを選択し作成しましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/c3e4c297-d1be-601d-9c24-c7c2d05ba13e.png)
「Available authentication methods」は「Use both legacy and IAM」にします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/d6dc8268-1124-42db-50ef-673435fc57d0.png)
※ 最初は 「Use only IAM」にしていたのですが、`one of _writer, _creator is required for this request` エラーが発生してうまく権限が得られなかったようなので、変更して接続し直しちゃいました。

翻訳サービスの時と同様に、アプリに接続して再ステージまで実施します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/918e2be0-1cb7-f545-cc53-a12bee14b84f.png)
ランタイムで環境変数を確認し、例の VCAP_SERVICES に Cloudant サービス用の値 (特に接続用の値 credentials) が追加されていることを確認しておきましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/cbf047f2-0856-e9ac-368f-6e779c848976.png)

## CloudantサービスのAPI化

[このあたり](https://github.com/IBM-Cloud/get-started-node/blob/master/server.js) を参考に、Cloudantサービス用のAPIも作成しておきましょう。まずは @cloudant/cloudant モジュールを導入。

```
npm install --save @cloudant/cloudant
```

Cloudantサービスの接続とDBの準備まで以下のようなコードにしてみました。翻訳サービスの時と同様に、`VCAP_SERVICES` 環境変数が設定されていればそれを利用します。

```javascript:Server.js
const Cloudant = require('@cloudant/cloudant');

let cloudant_credentials = {
	// <your credentials>
};
try {
	let db_obj = JSON.parse(process.env.VCAP_SERVICES);
	if (!!db_obj.cloudantNoSQLDB[0].credentials) {
		cloudant_credentials = db_obj.cloudantNoSQLDB[0].credentials;
	}
} catch (e) {}
const cloudant = Cloudant(cloudant_credentials);

const cloudant_dbname = 'rtk-lt';
cloudant.db.create(cloudant_dbname, function(err, data) {
	if(!err) //err if database doesn't already exists
		console.log("Created database: " + cloudant_dbname);
});
const db = cloudant.db.use(cloudant_dbname);
```

例によってこのままではローカル環境で動作しませんので、`<your credentials>` の部分に資格情報をコピペしておいてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/a103f034-2b78-63d3-1da2-432aa311ec71.png)
DBにオブジェクトを追加する POST API を以下のように定義します。

```javascript:Server.js
app.post('/add', (req, res) => {
	if (req.body) {
		db.insert(req.body, function(err, body, header) {
			if (err) {
				console.log('[db.insert] ', err.message);
				res.status(500).send("Error");
				return;
			}
			req.body._id = body.id;
			res.status(200).send(req.body);
		});
	}
});
```

POST で得られたオブジェクトを、中身を確認せずに、そのまま Cloudant DB に insert してしまう、というかなり豪快な仕様になっています。実際に利用する場合には、値チェックして、ちゃんとオブジェクト作り直すなど用心深いコードに書き直すほうが良いでしょうw

さて、登録するだけではダメですね。参照するための GET API も定義しましょう。

```javascript:Server.js
app.get('/list/:user', (req, res) => {
	if (!!req.params.user) {
		db.find({ selector: { user:req.params.user }, limit:50 }, function(err, result) {
			if (err) {
				console.log('[db.find] ', err.message);
				res.status(500).send("Error");
				return;
			}
			let json = '[' + result.docs.map(doc => JSON.stringfy(doc)).join(',') + ']';
			res.status(200).send(json);
		});
	}
	res.status(400).send("Bad Request");
	return;
});
```

こちらもシンプルなコードですが、ユーザー名を Express の [名前付き パラメーター](https://garafu.blogspot.com/2017/03/nodejs-express-url-routing.html) 機能で得ているのがポイントでしょうか。この機能、楽でいいですよね。

ロジックとしては Cloudant DB の find 関数で、検索条件としては user のみを指定しています。`limit:50` で返すオブジェクトの数を50個までに制限しているところは、今後、考慮の余地がありそうな気もしますね。

また、オブジェクトの配列を

```javascript
'[' + result.docs.map(doc => JSON.stringfy(doc)).join(',') + ']'
```

のように map と join を組み合わせてテキスト化するのは好みのパターンなのですが、、、今回は JSON 形式が欲しいだけなので、単に `JSON.stringfy(result.docs)` で十分な気がしますw

# というわけで

さて、これで Node.js アプリに、ログを保存し、またそれを入手する API を追加することができました。必要なサービスが揃ったので、次回は [(5) フロントエンド側の実装](https://qiita.com/yamachan360/items/de57df20dc7de5665a44) を実施します。GitHub 上の [ソースコード](https://github.com/yamachan/rtk-lt) も参照してみてください。