Technical Articles
capireのCookbook(Reuse, Compose, and Integrate)翻訳
はじめに
本ドキュメントは2022年3月7日時点ののの一部であるを短く日本語ドキュメントにまとめたものです。以降、Reuse、ComposeおよびIntegrateはそれぞれ”あるオブジェクトの再利用すること”、”別オブジェクトと結合させて新たなオブジェクトを用意すること”、“あるオブジェクトに別オブジェクトの機能を埋め込むこと”を意味するキーワードとして利用します。
本ドキュメントは上記時点のCookbookを参照してまとめられています。最新の情報は必ずCookbookをご確認ください。また、本ドキュメントにおける翻訳は単語の正確な翻訳よりも文脈の掴みやすさを重視して翻訳しています。正確な情報を入手される場合も必ずCookbookをご確認ください。
翻訳まとめ
Reuse, Compose, and Integrate
CAPのプロジェクトを再利用したり拡張したい場合に、どのような手段を取ることが可能か紹介します。
目次
-
はじめに
-
使用シナリオ
-
サンプルプロジェクト
-
試すときに必要な用意
-
-
インポートによるパッケージの再利用
-
npmレジストリから
npm add/install
でインポート -
その他のソースからインポート
-
再利用における“組込み”と“統合”
-
-
インポートされたモデルの再利用
-
using from
命令 -
index.cds
を使用した組込み -
その他組込み方法
-
インポートした定義の使用および拡張
-
-
インポートしたコードの再利用
-
Node.jsの場合
-
- インポートしたUIの再利用
- サービスの統合
1. はじめに
パッケージのインポートによって、CAPはモデル、コード、初期データやi18nバンドルを再利用可能です。
1-1. 使用シナリオ
CAPのreuse、composeおよびintegrateテクニックを使用することで、開発者は下記のようなさまざまな再利用シナリオに対応可能です。
-
Verticalized/Composite Solutions(垂直型compose手法) — 開発者はいくつかのパッケージ(もしくはサービス)を選択し、マッシュアップするように新たなCAPアプリケーションを開発します。
-
Prebuilt Extension Packages(事前定義の拡張パッケージ) — 上記垂直型compose手法で利用されることなどを前提に、開発者は新たな拡張パッケージを用意します。
-
Prebuilt Integration Packages(事前定義の統合パッケージ) — 上記垂直型compose手法で利用されることなどを前提に、開発者は新たな統合パッケージを用意します。
-
Prebuilt Business Data Packages(事前定義ビジネスデータのパッケージ) — 開発者は初期データをパッケージにして提供します。この対象にはLanguages, Countries, Regions, Currenciesなどのデータが一般に含まれます。
-
Customizing SaaS Solutions(利用側によるアプリケーション拡張) — 開発者によってCAPアプリケーションを提供される側の人員が提供されたアプリケーションを拡張してカスタマイズします。
1-2. サンプルプロジェクト
SAPはその公式GitHubでをサンプルプロジェクトとして公開しています。
-
は本サンプルプロジェクトにおける基本的な機能を提供し、再利用されます。
-
はいくつかのパッケージで再利用される共通機能を“事前定義の拡張パッケージ”として提供し、初期データを”事前定義ビジネスデータのパッケージ”として提供します。
-
は再利用されるパッケージです。
-
は再利用されるパッケージです。
-
は上記パッケージたちを利用した”利用側によるアプリケーション拡張”のパッケージです。
1-3. 試すときに必要な用意
以下の手順でを試していただくことが可能です。
1) cap/samplesをクローンし、ローカルのnpm registryに登録する
git clone https://github.com/sap-samples/cloud-cap-samples samples
cd samples
npm install
npm run registry
@capire/...
パッケージを別プロジェクトから参照させる場合、上記npm runコマンドは動かし続けてください。
2) 起動する
cds init sample
cd sample
npm i
# ... run the upcoming commands in here
2. インポートしたパッケージの再利用
CAPはnpmの仕組みを用いてパッケージを再利用可能です。下記の図はパッケージ再利用の基本的な手順です。
2-1. npmレジストリからnpm add/install
でインポート
npm add/install
を用いて開発中のパッケージに対して外部パッケージをインポート可能です。
npm add @capire/bookshop @capire/common
npm add
はnpm install
のエイリアスです。詳しくはをご参照ください。
上記のコマンドによりnode_modules
ディレクトリ配下にインポートしたパッケージが配置され、package.json
に下記の内容が追記されます。
{
"name": "sample", "version": "1.0.0",
"dependencies": {
"@capire/bookshop": "^1.0.0",
"@capire/common": "^1.0.0",
...
}
}
2-2. その他のソースからインポート
npmレジストリからのインポートに加え、ローカルのソースをインポートすることも可能です。ローカルの他CAPプロジェクトやtarball(.tgz)を使用できます。
npm add ~/Downloads/@capire-bookshop-1.0.0.tgz
npm add ../bookshop
2-3. 再利用における“組込み”と“統合”
パッケージを再利用するためにインポートすると、デフォルトではインポートされたすべての要素がインポート先のプロジェクトに含まれます(いわば”組込まれた”もしくは”埋め込まれた”というような状態になります)。例えば以下のような要素を含みます。
-
ドメインモデル(db/)
-
サービス定義(srv/.*.cds)
-
サービス実装(srv/.*.js)
-
i18nバンドル
-
初期データ(db/data/.*csv)
CAPではこのような組込みだけではなく、上記要素の一部だけを利用するような統合する使用方法も存在します。その方法は以下の“6. サービスの統合”に記載されています。
3. インポートされたモデルの再利用
すべてのインポートされた要素はインポート先のCAPプロジェクトに組み込まれていますが、それらのうちのどれをしようするかはインポート先の開発者に委ねられています。
補足:インポート先で参照しているすべてのインポート元モデルは公開されます。一方で、参照されていないすべてのインポート元モデルは公開されません。
3-1. using from
命令
using
命令を使って下記のようにモデルをインポートできます。
using from '@capire/bookshop';
using from '@capire/common';
cds
コンパイラはnode_modules
配下にあるインポートされたコンテンツを見つけてこれを取り込みます。
3-2. index.cds
を使用した組込み(全公開)
上記のusing from
命令はインポートされたパッケージがindex.cds
を持っていることを期待します。このindex.cds
はインポートされるプロジェクトのルートに配置して、します。実装例はを参照してください。
// 下記に含まれる定義をすべて公開します
using from './db/schema';
using from './srv/cat-service';
using from './srv/admin-service';
これにより、cds watch
起動時などに下記ログを参照できます。これによって組み込まれたアプリが再利用されていることを把握できます。
[cds] - connect to db > sqlite { database: ':memory:' }
> filling sap.common.Currencies from common/data/sap.common-Currencies.csv
> filling sap.common.Currencies_texts from common/data/sap.common-Currencies_texts.csv
> filling sap.capire.bookshop.Authors from bookshop/db/data/sap.capire.bookshop-Authors.csv
> filling sap.capire.bookshop.Books from bookshop/db/data/sap.capire.bookshop-Books.csv
> filling sap.capire.bookshop.Books_texts from bookshop/db/data/sap.capire.bookshop-Books_texts.csv
> filling sap.capire.bookshop.Genres from bookshop/db/data/sap.capire.bookshop-Genres.csv
/> successfully deployed to sqlite in-memory db
[cds] - serving AdminService { at: '/admin', impl: 'bookshop/srv/admin-service.js' }
[cds] - serving CatalogService { at: '/browse', impl: 'bookshop/srv/cat-service.js' }
3-3. その他組込み方法(部分公開)
もしすべてではなく部分的に公開したい場合、using from
命令を下記のように書き換えます。
using { CatalogService } from '@capire/bookshop/srv/cat-service';
このとき下記のようにcds watch
のログは確認できます。
[cds] - connect to db > sqlite { database: ':memory:' }
> filling sap.capire.bookshop.Authors from bookshop/db/data/sap.capire.bookshop-Authors.csv
> filling sap.capire.bookshop.Books from bookshop/db/data/sap.capire.bookshop-Books.csv
> filling sap.capire.bookshop.Books_texts from bookshop/db/data/sap.capire.bookshop-Books_texts.csv
> filling sap.capire.bookshop.Genres from bookshop/db/data/sap.capire.bookshop-Genres.csv
/> successfully deployed to sqlite in-memory db
[cds] - serving CatalogService { at: '/browse', impl: 'bookshop/srv/cat-service.js' } <- Catalogサービスのみ公開されています
3-4. インポートした定義の使用および拡張
インポートしたモデルは下記のように組み合わせて拡張するように使用することもできます。
using { sap.capire.bookshop.Books } from '@capire/bookshop';
using { ReviewsService.Reviews } from '@capire/reviews';
// インポートしたreviewとbookshopをここで拡張(マッシュアップ)しています
extend Books with {
reviews : Composition of many Reviews on reviews.subject = $self.ID;
rating : Decimal;
}
4. インポートしたコードの再利用
モデルに加えてサービス実装もインポートする場合、インポート元のモデル定義に@impl
アノテーションでサービス実装を紐づけます。多くのサンプルコードではcat-service.cds
にサービス定義を紐づけるときは同名のjsファイルを用意して紐づけを自動で実現していますが、その代わりに@impl
アノテーションを使用します。
その手順は以下の通りです。
a. @impl
アノテーションを追加
using { CatalogService } from '@capire/bookshop';
annotate CatalogService with @impl:'srv/my-cat-service-impl';
b. @impl
アノテーションで指したファイル(srv/my-cat-service.impl.js
)を用意
module.exports = cds.service.impl (function(){
this.on (...) // add your event handlers
})
c. 下記のようにインポートした実装を呼び出し
const base_impl = require ('@capire/bookshop/srv/cat-service') // インポートした定義をインポート
module.exports = cds.service.impl (async function(){
this.on (...) // add your event handlers
await base_impl.call (this,this) // 定義を呼び出し
})
5. インポートしたUIの再利用
server.js
を用意し、express
でルート追加をするのとおなじように再利用を定義します。
const express = require('express')
const cds = require('@sap/cds')
// Add routes to UIs from imported packages
cds.once('bootstrap',(app)=>{
app.serve ('/bookshop') .from ('@capire/bookshop','app/vue')
app.serve ('/reviews') .from ('@capire/reviews','app/vue')
app.serve ('/orders') .from('@capire/orders','app/orders')
})
...
module.exports = cds.server
6. サービスの統合
上記のような再利用ではなく、開発中のアプリの一部に対して外部サービスをライブラリのように使用する(統合する)方法も利用できます。この方法を使用することで、開発するアプリケーションたちをマイクロサービスとして構成できます。これは以下の手順により実装します。
a. 外部サービスのAPI定義をインポート
外部サービスのAPI定義を2. インポートしたパッケージの再利用の方法に従ってインポートします。もしくは外部サービスのAPI定義ファイル(edmx
)のみが手元にある場合、cds import
コマンドによりサービスをインポートします。
"dependencies": {
"@capire/bookshop": "^1.0.0",
"@capire/reviews": "^1.0.0",
"@capire/orders": "^1.0.0",
"@capire/common": "^1.0.0",
...
},
b. インポートしたサービスをサービス定義内で使えるように設定
package.json
内のに下記のようにインポートするサービス情報を設定します。cds import
でサービス定義をインポートしている場合、model
の指す場所は典型的にはsrv/extenal/<your-imported-definition>.edmx
です。例えば、とを利用するプロジェクトを定義する場合であればのように定義します。
"cds": {
"requires": {
"ReviewsService": {
"kind": "odata", "model": "@capire/reviews" // @capire/reviewsで定義されたodataサービスがReviewServiceという名前で使えるようになる
},
"OrdersService": {
"kind": "odata", "model": "@capire/orders"
},
}
}
c. インポートしたサービスの呼び出し
設定した接続先はcds.connect.to()
// 1. package.jsonで設定したCatalogServiceとReviewsServiceに接続するためのクライアントを取得
const CatalogService = await cds.connect.to ('CatalogService')
const ReviewsService = await cds.connect.to ('ReviewsService')
CatalogService.prepend (srv => srv.on ('READ', 'Books/reviews', (req) => {
console.debug ('> delegating request to ReviewsService')
const [id] = req.params, { columns, limit } = req.query.SELECT
// 2. クライアントを用いてサービス実行
return ReviewsService.tx(req).read ('Reviews',columns).limit(limit).where({subject:String(id)})
}))
上記実装例の完全版は