Technical Articles
SAP Cloud PlatformでのNode.js + SAP HANAアプリ開発 – ロジック/UI編
はじめに
本Blogでは、SAP Cloud PlatformでのNode.js + SAP HANAアプリ開発について、FAQサイトの構築を例に下記のトピックで紹介します。(本Blogシリーズの概要編はこちら)
- 開発ツール: Web IDE, その他
- ロジック: Node.js
- UI: Bootstrap + jQuery
- データベース: SAP HANA
- 認証(Authentication)と権限(Authorization): XSUAA
前回の開発ツール編に続き、今回はロジックとUI編です。(下図の②と③) ここでは、Cloud Foundry環境に依存する開発のお作法や、Node.jsアプリケーションからHANA DBへのアクセス方法、また、簡単にはなりますがUIについて説明していきます。
ロジック/UI
Cloud Foundryでは、提供されているBuildpackに基づいて自由に開発言語を選択することができます。本アプリケーションは、Node.jsで開発をしていますが、Java、PHP、Go、Python、.Net Coreなど豊富な選択肢があるため、開発経験や好みの開発フレームワークに応じた開発が可能です。また、S/4HANAのSide by Sideの拡張開発やアドオン開発においては、S/4HANA Cloud SDKがJavaとJavaScript(TypeScript)向けに提供されていますので、Node.jsを利用したS/4HANAの効率的な開発が可能という点も意識頂ければと思います。
このFAQサイトでは、FAQ情報の検索がメインであるため、データの格納先であるSAP HANAにアクセスし、抽出したデータをUI側が利用し易いようにJSON形式で出力するのが、主な処理となります。以下詳細です。
1. Node.js / UIフレームワーク
本アプリケーションでは、Node.jsのパッケージやUIのフレームワークとして下記を利用しています。
- Express: Node.jsフレームワーク
- EJS: Node.jsのテンプレートエンジン
- Bootstrap: HTML+CSSのUIフレームワーク
- JQuery: JavaScriptフレームワーク
- HANA Client: SAP HANA接続用のNode.jsクライアント
2. HANAへの接続 – HANA Client
まず前提となりますが、今回のアプリでは、HANAへのアクセスをODataサービス経由ではなく、一般的なDBへのアクセスと同じようにDBクライアントを使ったSQLでの実装例となります。そのため、対象のNode.jsプロジェクトにはHANA Clientパッケージを導入します。
npm install @sap/hana-client --save
HANA Clientは、上記以外にもnode-hdbがありますが、現在は上記のhana-clientの利用が推奨されます。また、@sap/hdbextは、@sap/hana-clientの拡張版になります。
下記がHANAにアクセスするためのコード例です。(SQLのクエリーは簡略化しています)
var express = require('express');
var router = express.Router();
// HANA Clientライブラリを読込み
var hana = require('@sap/hana-client');
var conn = hana.createConnection();
// HANA接続用パラメーターを設定
var conn_params = {
serverNode : <ホスト名>.dbaas.ondemand.com:<ポート番号>,
encrypt : true,
schema : <スキーマ名>,
uid : <ユーザーID>,
pwd : <パスワード>
};
// 検索機能が呼ばれた際に実行されるGetメソッド
router.get('/api/search', function(req, res, next){
// 検索キーワードをreqパラメーターから取得
var word = req.query.search;
// HANAに接続
conn.connect(conn_params, function(err) {
if (err) {
console.log("DB Error: DB Connection --- ", err);
var msg = [{msg: "DB Error: DB Connection"}];
res.json({searchResult: msg});
return;
}
var sql = 'SELECT * FROM "' + conn_params.schema + '"."<テーブル名>" WHERE CONTAINS (*, ?);';
var stmt = conn.prepare(sql);
// クエリー実行。結果はresultで取得
stmt.exec([word], function (err, result) {
if (err) {
console.log("DB Error: SQL Execution --- ", err);
}
stmt.drop();
conn.disconnect();
if (Object.keys(result).length == 0){
var msg = [{msg: "No items found."}];
res.json({searchResult: msg});
return;
}
// クエリーの実行結果をJSON形式で返す
res.json({searchResult: result});
});
});
});
HANA接続用のパラメーター定義において、重要なパラーメーターは”encrypt”です。これを”true”にしないと、SAP Cloud Platform上のHANAには接続ができないためご注意ください。
var conn_params = {
serverNode : <ホスト名>.dbaas.ondemand.com:<ポート番号>,
encrypt : true,
schema : <スキーマ名>,
uid : <ユーザーID>,
pwd : <パスワード>
};
また、その他の接続情報は、下図の通りCockpit上からHANAインスタンスのサービスキー情報で確認可能です。
3. HANAへの接続 – VCAP_SERVICEパラメーター
上記の通りHANA接続用パラメーターを定義することで、ローカルの開発環境からもNode.jsアプリケーションはHANAに接続可能です。一方で、Cloud Foundryにはアプリケーションがアクセス可能な環境変数として、VCAP_SERVICEというパラメーターが用意されています。
このVCAP_SERVICEには、アプリケーションが利用するCloud Foundry上のバッキングサービス(本件ではHANAインスタンスや認証のXSUAAインスタンス)のアクセス情報が含まれるため、アプリケーションのコード内では、下記のようにこのパラメーターを参照する形にする方がより汎用的になります。
if (process.env.VCAP_SERVICES){
// Cloud Foundryでの実行時に利用
var vcap_services = JSON.parse(process.env.VCAP_SERVICES);
var conn_params = {
serverNode : vcap_services.hana[0].credentials.host + ":" + vcap_services.hana[0].credentials.port,
encrypt : true,
schema : vcap_services.hana[0].credentials.schema,
sslValidateCertificate: false,
uid : vcap_services.hana[0].credentials.user,
pwd : vcap_services.hana[0].credentials.password
};
} else {
// ローカル環境での実行時に利用。
var conn_params = {
serverNode : <ホスト名>.dbaas.ondemand.com:<ポート番号>,
encrypt : true,
schema : <スキーマ名>,
uid : <ユーザーID>,
pwd : <パスワード>
};
}
1つ大事な点として、Cloud Foundry上での実行用パラメーター側には、”sslValidateCertificate”パラメーターを追加しています。これがないとディプロイ後のアプリケーションが下記のエラーを出力し、HANAにアクセスができないための対応です。
"Cannot create SSL context: SSL trust store cannot be found: /home/vcap/.ssl/trust.pem"
4. SQLの実行
続いて、HANA Clientを利用したSQL文作成のお作法についてです。
var sql = 'SELECT * FROM "' + conn_params.schema + '"."<テーブル名>" WHERE CONTAINS (*, ?);';
WHERE句の中で、”?”を使っていますがこれは変数になります。この”?”の中には下記のstmt文の中の”[word]”が代入されSQLが実行されます。変数が複数必要な場合には、SQL文の中に複数の”?”を設定し、[ ]の中にそれぞれの変数をカンマ区切りで設定することで可能です。(WHERE句の”CONTAINS”はあいまい検索用のオプションです)
stmt.exec([word], function (err, result) {
実行結果は、”result”変数にオブジェクト型として入ってくるため、JSON形式でレスポンスを返します。
res.json({searchResult: result});
ブラウザからアクセスすると、下図のようにJSON形式でデータを取得することが可能です。(検索ワードに”ライセンス”として実行した結果)
5. UI側でのデータ取得
UI側はJQueryを使っているため、下記JavaScriptでNode.jsからデータを取得しています。(コードの一部を抜粋)
// 画面の検索ボックスの入力内容を取得
var word = $("#searchBox").val();
// Node.js側で定義したデータ取得用のGetメソッドのエンドポイントを設定
var url = "./search/api/search?search=" + word;
// JQueryのJSONデータ取得メソッドを実行
$.getJSON(url, function(data){
var dataSet = new Array;
var i = 0;
// データ取得結果を配列に格納
$(data.searchResult).each(function(){
dataSet[i] = new Array(this.faqId, this.score, this.category, this.serviceNameS, this.question, this.regDate, this.views);
i++;
});
// dataTableというテーブル用のライブラリに、配列データを格納
if(dataSet.length != 0){
$("#faqList").dataTable().fnAddData(dataSet);
}
});
最後に、上記までの実装結果が下図のようになります。
ロジック/UI編は以上になります。HANA DBを使ったカスタムアプリケーション開発においても、従来通りのDBクライアント経由でのアクセスも可能ですので、実装しやすいかと思います。ぜひ、今後のHANAのネイティブアプリケーション開発の参考にしていただけますと幸いです。
それでは、次回はデータベース編です。CDSでのデータベースモデリングや、あいまい検索(Fuzzy Search)などについてご紹介したいと思います。