0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CDS-TyperでTypeScriptを使用したCAP開発をする

Last updated at Posted at 2023-12-25

はじめに

CDS-Typerは、CAPのデータモデルを参照したTypeScript用の型定義ファイル(.ts)を生成するツールです。コーディング時に型を使用したオートコンプリートができるようになります。

使い方は以下のドキュメントに書かれていますが、やってみてつまづいた点があったので、解決方法を含めて記事に残します。

ソースコード:https://github.com/miyasuta/cap-cds-typer

前提

  • 開発環境はSAP Business Application Studio
  • TypeScriptを使用するため、以下のパッケージをグローバルにインストール
npm i -g typescript ts-node
  • VS CodeまたはBASの設定で、CDS > Type Generatorが有効になっていることを確認
    image.png

ステップ

  1. CAPのプロジェクトを作成
  2. .tsconfigファイルを作成
  3. CDS-Typerを追加
  4. .cdsファイルを作成
  5. サービスを実行
  6. イベントハンドラを実装
  7. Cloud Foundryにデプロイ

参考:CDS-Typer | Capire

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": ".",とする必要があります。

参考:Integrate Into TypeScript Projects

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というフォルダができます。
image.png

@cds-modelsフォルダの中に、dbフォルダやsrvフォルダで定義したエンティティの型を定義した.tsファイルが作成されています。.cdsファイル側を変更すると、これらのファイルに自動的に反映されます。
image.png
image.png

@cds-modelsフォルダが自動で生成されない場合は、以下のコマンドを実行します。

npx @cap-js/cds-typer '*' --outputDirectory @cds-models

参考:CDS Typer: @cds-models folder not generated

2025年3月のリリースで、cds watch実行時に自動的に@cds-modelsフォルダが生成されるようになりました

@cds-modelsフォルダは.gitignoreに追加されるので、この状態ではGitリポジトリに格納されません。リポジトリからクローンしたプロジェクトには含まれていないことに注意が必要です。
image.png

データモデルに少し手を加えて、以下のようにします。

db/data-model.cds
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';
}
srv/cat-service.cds
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()
}}

以下のワーニングが出たら、指示通りにnpm i --save-dev @types/nodeを実行します。その後、一旦ファイルを閉じて開くとエラーが解消します。
image.png

ドキュメントでは、require('#cds-models/...')により型定義をインポートしていますが、この方法だとオートコンプリートが利かないのでawait importを使用する必要があります。
参考:Code completion with CDS Typer does not work

これにより、使用可能なプロパティやメソッドが提案されるようになります。
image.png

存在しないプロパティを指定した場合はエラーになります。
image.png

OrdersのFiori Previewから動作を確認します。
image.png

Orderを登録すると、Amountが自動計算されました。
image.png

7. Cloud Foundryにデプロイ

TypeScriptで作成したCAPプロジェクトのビルド、デプロイ方法については過去のブログを参考にします。

7.1 ビルド用スクリプトを追加

  • package.jsonに以下のスクリプトを追加
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を開いたときに以下のエラーになります。
image.png

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に変換されたイベントハンドラのファイルができています。
image.png

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と入力するとサービスにアクセスできます。
image.png
image.png

おわりに

この記事では、CDS-Typer使ってTypeScriptを使用したCAPの開発をしました。次回はここにTypeScriptで作るUI5アプリを追加したいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?