はじめに
CDS-Typerは、CAPのデータモデルを参照したTypeScript用の型定義ファイル(.ts)を生成するツールです。コーディング時に型を使用したオートコンプリートができるようになります。
使い方は以下のドキュメントに書かれていますが、やってみてつまづいた点があったので、解決方法を含めて記事に残します。
ソースコード:https://github.com/miyasuta/cap-cds-typer
前提
- 開発環境はSAP Business Application Studio
- TypeScriptを使用するため、以下のパッケージをグローバルにインストール
npm i -g typescript ts-node
ステップ
- CAPのプロジェクトを作成
- .tsconfigファイルを作成
- CDS-Typerを追加
- .cdsファイルを作成
- サービスを実行
- イベントハンドラを実装
- Cloud Foundryにデプロイ
1. CAPのプロジェクトを作成
以下のコマンドでCAPのプロジェクトを作成します。
cds init <プロジェクト名>
2. tsconfig.jsonファイルを作成
Type Scriptを使用するため、プロジェクトのルートにtsconfig.jsonファイルを作成します。
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./gen/srv/srv",
"rootDir": ".",
"baseUrl": "./",
"moduleResolution": "node",
"skipLibCheck": true,
"preserveConstEnums": true,
"sourceMap": false,
"allowJs": true,
"strict": true,
"strictNullChecks": false,
"strictPropertyInitialization": false,
"esModuleInterop": true,
"paths": {
"#cds-models/*": [
"./@cds-models/*/index.ts"
]
}
},
"include": [
"./srv/**/*"
]
}
参考にしたプロジェクトでは"rootDir": "./srv",
となっていましたが、CDS-Typerはプロジェクトのルートに型定義ファイルを生成するので、そこも対象に含めるよう"rootDir": ".",
とする必要があります。
3. CDS-Typerを追加
以下のコマンドでCDS-Typerを追加します。
cds add typer
これにより、package.jsonに@cap-js/cds-typerが追加されます。
"devDependencies": {
"@cap-js/sqlite": "^1",
"@cap-js/cds-typer": ">=0.1"
},
npm i
コマンドで追加したDependencyをインストールします。
4. .cdsファイルを作成
以下のコマンドで、サンプルのデータモデルを作成します。
cds add sample-tiny
.cdsファイルが作成されると同時に、プロジェクトのルートに@cds-models
というフォルダができます。
@cds-models
フォルダの中に、dbフォルダやsrvフォルダで定義したエンティティの型を定義した.tsファイルが作成されています。.cdsファイル側を変更すると、これらのファイルに自動的に反映されます。
@cds-models
フォルダが自動で生成されない場合は、以下のコマンドを実行します。
npx @cap-js/cds-typer '*' --outputDirectory @cds-models
参考:CDS Typer: @cds-models folder not generated
※2025年3月のリリースで、cds watch
実行時に自動的に@cds-models
フォルダが生成されるようになりました
データモデルに少し手を加えて、以下のようにします。
namespace my.bookshop;
entity Books {
key ID : Integer @title: 'Book ID';
title : String @title: 'Title';
stock : Integer @title: 'Stock';
price: Integer @title: 'Price'; //追加
}
//追加
entity Orders {
key ID: UUID @title: 'Order ID';
book: Association to Books @title: 'Book';
quantity: Integer @title: 'Quantity';
amount: Integer @title: 'Amount';
}
using my.bookshop as my from '../db/data-model';
service CatalogService {
@readonly entity Books as projection on my.Books;
@odata.draft.enabled
entity Orders as projection on my.Orders;
}
annotate CatalogService.Orders with @(
UI: {
LineItem : [
{
$Type : 'UI.DataField',
Value : ID,
},
{
$Type : 'UI.DataField',
Value : book_ID,
},
{
$Type : 'UI.DataField',
Value : quantity,
},
{
$Type : 'UI.DataField',
Value : amount,
}
],
HeaderInfo : {
$Type : 'UI.HeaderInfoType',
TypeName : 'Order',
TypeNamePlural : 'Orders',
},
Identification : [
{
$Type : 'UI.DataField',
Value : book_ID,
},
{
$Type : 'UI.DataField',
Value : quantity,
},
{
$Type : 'UI.DataField',
Value : amount,
}
],
Facets : [
{
$Type : 'UI.ReferenceFacet',
Target : '@UI.Identification',
},
],
}
){
amount @Common : { FieldControl : #ReadOnly, }
};
5. サービスを実行
以下のコマンドでサービスを実行します。
cds-ts watch
通常、cds watch
コマンドを使いますが、TypeScriptの場合はcds-ts watch
を使用します。
6. イベントハンドラを実装
TypeScriptでイベントハンドラを実装します。srvフォルダの中にcat-service.ts
ファイルを作成し、以下のコードを実装します。Order登録時に本の価格をDBから取得し、数量と掛け合わせて金額(amount)を算出します。
import cds from '@sap/cds';
module.exports = class CatalogService extends cds.ApplicationService { async init() {
const { Book, Books, Order } = await import('#cds-models/CatalogService')
this.before('CREATE', Order, async(req) => {
console.log('Create Order called')
//calculate amount
const { price } = await SELECT .one (Books, b => {b.price}) .where `ID = ${req.data.book_ID}`
console.log('price: ', price)
req.data.amount = req.data.quantity * price
})
return super.init()
}}
ドキュメントでは、require('#cds-models/...')
により型定義をインポートしていますが、この方法だとオートコンプリートが利かないのでawait import
を使用する必要があります。
参考:Code completion with CDS Typer does not work
これにより、使用可能なプロパティやメソッドが提案されるようになります。
OrdersのFiori Previewから動作を確認します。
7. Cloud Foundryにデプロイ
TypeScriptで作成したCAPプロジェクトのビルド、デプロイ方法については過去のブログを参考にします。
7.1 ビルド用スクリプトを追加
- package.jsonに以下のスクリプトを追加
"scripts": {
...
"build:cf": "npm run build:cds && npm run cleanup:ts && npm run build:ts",
"build:ts": "tsc",
"build:cds": "cds build --production",
"cleanup:ts": "npx rimraf gen/srv/srv/*.ts"
}
※rimrafを使うためnpm i rimraf --save-dev
でインストールしておく必要があります。
7.2 Cloud Foundry環境で必要な設定を追加
cds add hana --for production
cds add xsuaa --for production
cds add approuter --for production
xs-security.jsonファイルにredirect-urisを追加します。
{
"scopes": [],
"attributes": [],
"role-templates": [],
"oauth2-configuration": {
"redirect-uris": [
"https://*.hana.ondemand.com/login/callback"
]
}
}
これがないと、ApprouterのURLを開いたときに以下のエラーになります。
7.3 mta.yamlを生成
cds add mta
mta.yamlのビルドコマンドを以下のように変更します。
build-parameters:
before-all:
- builder: custom
commands:
- npm install
- npm run build:cf
7.4 ビルド
mbt build -t gen --mtar mta.tar
genフォルダを見ると、.jsに変換されたイベントハンドラのファイルができています。
7.5 デプロイ
cf deploy gen/mta.tar
ターミナルに表示されたApprouterのURLから入って確認します。
Application "cds-typer" started and available at "xxx-dev-cds-typer.cfapps.us10-001.hana.ondemand.com"
最初は(index.htmlファイルがないため)Not Foundとなりますが、/odata/v4/catalog/$metadata
と入力するとサービスにアクセスできます。
おわりに
この記事では、CDS-Typer使ってTypeScriptを使用したCAPの開発をしました。次回はここにTypeScriptで作るUI5アプリを追加したいと思います。