Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
susumususu
Advisor
Advisor
1,679

はじめに


本Blogでは、SAP Cloud PlatformでのNode.js + SAP HANAアプリ開発について、FAQサイトの構築を例に下記のトピックで紹介します。(本Blogシリーズの概要編はこちら)

  1. 開発ツール: Web IDE, その他

  2. ロジック: Node.js

  3. UI: Bootstrap + jQuery

  4. データベース: SAP HANA

  5. 認証(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)などについてご紹介したいと思います。