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


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

目次

DBにアクセスしよう

Cloudantサービスの作成と接続

カタログの「データベース」からNoSQL DBである「Cloudant」サービスを選択し作成しましょう。

「Available authentication methods」は「Use both legacy and IAM」にします。

※ 最初は 「Use only IAM」にしていたのですが、one of _writer, _creator is required for this request エラーが発生してうまく権限が得られなかったようなので、変更して接続し直しちゃいました。

翻訳サービスの時と同様に、アプリに接続して再ステージまで実施します。

ランタイムで環境変数を確認し、例の VCAP_SERVICES に Cloudant サービス用の値 (特に接続用の値 credentials) が追加されていることを確認しておきましょう。

CloudantサービスのAPI化

このあたり を参考に、Cloudantサービス用のAPIも作成しておきましょう。まずは @cloudant/cloudant モジュールを導入。

npm install --save @cloudant/cloudant

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

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> の部分に資格情報をコピペしておいてください。

DBにオブジェクトを追加する POST API を以下のように定義します。

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 も定義しましょう。

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 の 名前付き パラメーター 機能で得ているのがポイントでしょうか。この機能、楽でいいですよね。

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

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

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

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

というわけで

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