Technical Articles
CAPでSAP HANA CloudのテーブルをODataサービスとして公開する
SAP HANAデータベースにあるデータを外部に公開するユースケースではODataを使用することを推奨しています。
2019年からSAP では数々のプロジェクトで得た経験に基づいて、統一されたクラウドアプリケーションの開発手法Cloud Application Programming model (CAP)を構築し、提供しています。
CAPは、サービス及びアプリケーションを構築するための言語、ライブラリ、ツールのフレームワークです。
ベストプラクティスを凝縮し「ゴールデンパス」を提供しています。
開発過程で繰り返し発生する作業に対して、すぐに使える豊富なソリューションに沿って開発者をガイドします。
CAPのプロジェクトでは、技術的な分野を掘り下げずに、ドメインに重点を置いて開発を進めることができます。
このブログでは、SAP Cloud Application Programming Modelを使用してSAPHANA Cloudにテーブルを作成し、そのテーブルをODataサービスとして公開します。
この方法では、ODatav4.0を使用してデータを公開します。 ODatav2.0を使用してデータを公開する従来のxsodataメソッドとは対照的です。
前提
- SAP Business Technology PlatformアカウントでSAP HANA Cloudインスタンスを作成
(トライアルでも可能)
開発環境の準備
HANA Cloudインスタンスがセットアップされ、開始する準備ができたら、サブアカウントでサブスクリプションを開き、SAP Business ApplicationStudioをクリックします。
新しいDev Spaceを作成します。
SAP Cloud Business Application テンプレートを選択し、開発スペース名を指定します。
ステータスが「開始中」から「実行中」に変わったら、開発スペース名の付いたタイルをクリックします。
バックグラウンドで、Dev Spaceには、CAPアプリケーションの開発に必要なコンポーネントが用意されています。たとえば、ノードJSやCDSなど。
Business Application Studioで開発すると、ローカルPCに何もインストールする必要がありません。
テンプレートからプロジェクトを作成
これで、Business Application Studioが起動、構成され、使用できるようになりました。 Welcomeタブで、[テンプレートからプロジェクトを作成]をクリックします。
@sap/capテンプレートを選択します。
プロジェクトにSAP HANA関連の機能を含めるには、[hana]チェックボックスをオンにします。
舞台裏で、プロジェクトが生成されます。完了すると、画面に戻り、プロジェクトのワークスペースを開くためのポップアップメッセージボックスが右下に表示されます。 [新しいワークスペースで開く]ボタンをクリックします。
エディターが新しいワークスペースで開き、CAPアプリの開発を開始できるようになります。
画面の下部にある青いバーに、スペースがCloud Foundyで設定されていないことに注意してください。このバーをクリックして、Business Application StudioをODataサービスをデプロイ先のCloud Foundryスペースに接続します。
Cloud Foundryエンドポイントを記入し、クレデンシャルを入力して、デプロイ先のスペースを選択します。接続に必要な情報はSAP Business Technology PlatformのCockpitに記載されています。
データモデルの作成
これで、Business Application StudioがCloud Foundryスペースに接続されました。
データベースに作られるデータモデルを定義してみましょう!
データモデルはdbフォルダーの仲の.cdsファイルで定義されます。
左側のファイル構造から、dbフォルダーを右クリックし、新しい.cdsファイルを作成します。
下記のスクリーンショットでは”schema.cds”というファイル名で作成しています。ファイル名は任意です。
このファイルは、HANAデータベースにデプロイされるすべてのオブジェクト(テーブル、ビュー)を定義します。
schema.cdsファイルの中に最初のCAP構造を作成します。
namespace scp.cloud;
using {
cuid,
sap.common
} from '@sap/cds/common';
entity SafetyIncidents : cuid {
title : String(50) @title : 'Title';
description : String(1000) @title : 'Description';
}
この例では、namespaceをscp.cloudとして定義しています。
3行目~6行目で@ sap / cds / commonライブラリをと呼びcuidアスペクトを使用します。
8行目ではcuidを用いて、エンティティSafetyIncidentsでID列を自動的に定義します。
アスペクトについての詳細はCAPドキュメントをご参照ください。
CAPで定義されたエンティティは、データベースのテーブルとしてデプロイされます。
トップメニューに移動し、[ターミナル]-> [新しいターミナル]を選択して、ターミナルウィンドウを開きます。
プロジェクトフォルダー内で、コマンドnpm installを実行します。
次に、CAP開発では欠かせない便利なコマンドcds watchを使います。
プロジェクトに.cds、.json、または.jsファイルを追加や変更するたびに、サーバーは自動的に再起動して新しいコンテンツを提供し始めます。
ではcds watch
を実行します。
そのコマンドが実行されている限り、プロジェクト構造を変更するたびに、プロジェクトの変更が自動的に保存および再デプロイされます。
数秒後、cds watchコマンドがODataサービスを生成します。
また、schema.cdsに定義されたテーブルを開発環境内のSQLiteデータベースに作成します。
[公開して開く]ボタンをクリックして、最初の空のサービスがブラウザウィンドウに表示されるかどうかを確認します。
空っぽのサービスが表示されます。
ODataサービスとしてエンティティを公開
先ほどのステップでSafetyIncidentsエンティティがdbフォルダーで定義されました。
srvフォルダーでサービス定義を追加することでODataサービスとして公開できます。
早速やってみましょう! srvフォルダ内にincidentService.cdsという新しいファイルを作成します。
incidentService.cdsの中身がこちら:
using scp.cloud from '../db/schema';
service IncidentService {
entity SafetyIncidents as projection on cloud.SafetyIncidents;
}
1行目では、前に作成したschema.cdsファイルを参照することを定義しています。
2行目では、”cloud.SafetyIncidents”をIncidentServiceというODataサービスとして公開しています。
まとめると:
DB entity : cloud.SafetyIncidents
OData service entity : SafetyIncidents
OData Service : IncidentService
プレビュー画面をもう一度開くと、SafetyIncidentsエンティティが表示されます。
プレビュータブを閉じた場合は、[View]:[Find command]をクリックしてから、[Port:Preview]コマンドを検索することで、いつでも再度開くことができます。
これにより、現在公開されているポートのプレビューが開きます。
それでは、データをテーブルに挿入しましょう。
dbフォルダー内にdataという新しいフォルダーを作成することから始めます。
ID;title;description
067460c5-196c-4783-9563-ede797399da8;Broken machine;The printing machine is leaking
efec3e9f-ceea-4d17-80a7-50073f71c322;Software bug;The computer is on fire
ファイル名は、データを挿入するnamespace(scp.cloud)およびエンティティ名(SafetyIncidents)と一致する必要があります。
スクリーンショットに示されているように、dbフォルダーの下にデータフォルダーのスペルが正しいこと、およびファイル名のスペルが正しいことを確認してください。csvファイルで列名が正しいことをも確認してください。
cdsウォッチがまだ実行されている場合は、一度停止し、ターミナルでcds runを実行して、データがSQLiteテーブルにインポートされていることを確認します。
> filling scp.cloud.SafetyIncidents from db/data/scp.cloud.SafetyIncidents.csv メッセージでデータがインポートされていることがわかります。
これで実行中です。
サービスを開いてSafetyIncidentsエントリをクリックすると、データが表示されます。
これで、開発環境内のSQLiteデータベースにデプロイされたテーブルが作成され、テストデータも格納されました。
このテーブルは、部からアクセスできるODataサービスを介して公開されます。
データモデル、およびODataサービスをSAP HANA Cloudにデプロイ
ローカル環境のSQLiteでバックエンドサービスを実行しているので、次はこのプロジェクトをSAP HANA Cloudで実行します。
今まで作成したもの
- インシデント管理アプリケーションのスキーマ(データモデル)をschema.cdsで定義しました。
- データを公開するためのODataサービスをincidentService.cdsで定義しました。
- SQLiteにデータをロードし、ODataサービスを通して確認しました。
HANACloud用にプロジェクトを準備
SAP HANA Cloudでは、CDSモデルはhdbcdsではなくhdbtableおよびhdbview形式でデプロイされます。
package.jsonを編集して、deploy-formatをhdbtableに設定します。
package.jsonの「cds」セクションに次の行を追加します。
"hana" : { "deploy-format": "hdbtable" }
下記のスクリーンショットのように編集します。
プロジェクトをビルド
Node.JSの世界には、NODE_ENVという環境変数があります。
これまで、development「開発」環境を使用してきました。その変数をproduction「本番」に切り替える時が来ました。
CDSの動作に影響します。プロジェクトをSAP Business Technology Platformにデプロイするには、ターミナルウィンドウから次のコマンドを実行する必要があります。
- すでに実行されている場合は、CTRL + Cを使用して実行中のCDSプロセスを停止します。
export NODE_ENV=production
コマンドを実行cds build/all --clean
コマンドを実行
このコマンドは、関連するすべてのHANAアーティファクトをビルドし、それらを新しく作成されたgenフォルダに配置します。
genフォルダを展開すると、DBとSRVの2つのフォルダが表示されます。ご想像のとおり、DBフォルダーにドリルインすると、HANA DBアーティファクトが表示され、SRVにドリルインすると、そこにも新しいファイルがあります。
HDI Containerを作成しオブジェクトをデプロイ
ビルドプロセスが完了したら、(1)Cloud FoundryでHANAデプロイメントインフラストラクチャ(HDI)コンテナーを作成し、(2)HANAアーティファクトをデプロイし、(3)SRVアーティファクトをデプロイするために、3つのコマンドを連続して実行します。
ビルドプロセスの結果、HDIコンテナを作成するために必要なコマンドがターミナルに示されていることに注意してください。
次のコマンドを実行し、cap_project-dbというHDIコンテナを作ります:cf create-service hana hdi-shared cap_project-db
コンテナの作成には数分かかる場合があります。
注:以下のスクリーンショットでは、コマンドcf create-service hanatrial hdi-shared cap_project-dbを実行しています。古い「HANA as a Service」にデプロイしています。 パラメータhanaを使用することでHANA Cloudにデプロイします。
これにより、生成されたhdbtableオブジェクトとhdbviewオブジェクトがHDIコンテナにデプロイされます。
HDIコンテナの作成には数分かかります。
次のコマンドを実行します: cf push -f gen/srv --random-route -k 320M
これにより、ODataサービスを公開するNode.JSアプリケーションがBTPにデプロイされます。開発者だけでなく、ユーザーもアクセスできるようになります。.
3つのコマンドがすべて実行されたら、ターミナルウィンドウの下部に指定されたルートが表示されます。
--random-route
オプションを使用しましたので、ランダムなURLを作成するようにプロセスに指示しました。
生成されたルートURLをブラウザに貼り付けて、インターネット上で利用可能であることを確認してみましょう。
Webブラウザーを開き、新しく作成したルートURLを貼り付けます。
エンティティを開くと、次のような見慣れた画面が表示されます。
SAP Business Technology PlatformにデプロイされたODataサービスは、インターネット上で利用可能になり、永続層としてSAP HANA Cloudを使用しています。
お疲れ様でした。SAP HANA Cloudにデータモデル、そしてBTPにODataサービスをデプロイしました。
より複雑なデータモデルの例
実際はより複雑なODataサービスを構築される方が多いと思います。参考コードを少しご紹介します。
次のステップとしては例えばこのサービスを使用して、Fiori UIを作成し、ユーザーが安全インシデントを報告できるアプリケーションを作成します。
以下のエンティティ定義とCAPドキュメントを調べて、CAPがどのように開発プロセスを楽にするかを学びましょう。
schema.cds
の中身を下記のコードに置き換えます:
namespace scp.cloud;
using {
cuid,
managed,
sap.common
} from '@sap/cds/common';
entity SafetyIncidents : cuid, managed {
title : String(50) @title : 'Title';
category : Association to Category @title : 'Category';
priority : Association to Priority @title : 'Priority';
incidentStatus : Association to IncidentStatus @title : 'IncidentStatus';
description : String(1000) @title : 'Description';
incidentResolutionDate : Date @title : 'ResolutionDate';
assignedIndividual : Association to Individual;
incidentPhotos : Association to many IncidentPhotos
on incidentPhotos.safetyIncident = $self;
incidentHistory : Association to many IncidentHistory
on incidentHistory.safetyIncident = $self;
}
entity Individual : cuid, managed {
firstName : String @title : 'First Name';
lastName : String @title : 'Last Name';
emailAddress : String @title : 'Email Address';
safetyIncidents : Association to many SafetyIncidents
on safetyIncidents.assignedIndividual = $self;
}
entity IncidentHistory : cuid, managed {
oldStatus : Association to IncidentStatus @title : 'OldCategory';
newStatus : Association to IncidentStatus @title : 'NewCategory';
safetyIncident : Association to SafetyIncidents;
}
entity IncidentPhotos : cuid, managed {
@Core.IsMediaType : true imageType : String;
@Core.MediaType : ImageType image : LargeBinary;
safetyIncident : Association to SafetyIncidents;
}
entity IncidentsCodeList : common.CodeList {
key code : String(20);
}
entity Category : IncidentsCodeList {}
entity Priority : IncidentsCodeList {}
entity IncidentStatus : IncidentsCodeList {}
incidentService.cds
の中身を下記のコードに置き換えます:
using scp.cloud from '../db/schema';
service IncidentService {
entity SafetyIncidents as projection on cloud.SafetyIncidents {*,assignedIndividual: redirected to Individual };
entity Individual as projection on cloud.Individual {*,safetyIncidents : redirected to SafetyIncidents};
entity SafetyIncidentsNoImages as projection on cloud.SafetyIncidents{ID ,createdAt, priority, incidentStatus,description};
entity IncidentPhotos as projection on cloud.IncidentPhotos {*,safetyIncident : redirected to SafetyIncidents};
entity IncidentHistory as projection on cloud.IncidentHistory {*,safetyIncident : redirected to SafetyIncidents};
entity IncidentsByCategory as select from cloud.SafetyIncidents {count(ID) as categories:Integer,key category} Group By category;
@readonly entity Category as projection on cloud.Category;
@readonly entity Priority as projection on cloud.Priority;
}
これで履歴や写真も保存するインシデントサービスが作られます。
より深くCAPについて知りたい方はこちらをご参照ください。
[English Version of this blog]
Maxime SIMON