はじめに
この記事は、SAPアドベントカレンダー2025の12月12日分の投稿として執筆しています。
2021年頃までは、SAP Forms Service by AdobeはNeo環境でしか利用できませんでしたが、現在ではCloud Foundry(以下CF)環境でも利用可能になりました。今回はCF環境からの使い方をまとめました。
Neo環境の記事を参考にしても、CF環境ではロール設定などNeoにはなかった概念があり、躓いてしまいました。
私もそうですが、SAPのヘルプ、解読がとても難しい・・英語わからないので自動翻訳した日本語を理解するのも大変。
こういう記事は、なんぼあってもいいですからね。
SAPのヘルプと同じ手順ですが、ほんの少しでも誰かにとって大きな助けになるはずです。この記事がその一助になれば幸いです。
下記の公式ヘルプ手順に沿っています。
手順
1.エンティティの割り当て(サービスの有効化)
BTPコックピットからサブアカウント画面に移動し、
[エンティティの割り当て]>[サービスプランを追加]

AdobeFormServiceを探して以下チェックつける
●Free : 各々適切なサービスプランを選択
●Standard(アプリケーション) :これを選択しないと、のちに使用するテンプレートをアップロードするUI画面が使用できない。

今回はBASからAPIを使用してAdobeFormServiceを呼び出しPDF生成するので、こちらのサービスもチェック入れる。

2.ロールの割り当て
サブアカウント画面の[ロールコレクション]>[作成]
ロールコレクションを作成して、2つのロールを追加します。
✅ ADSAdmin
権限内容:
SAP Forms Serviceの設定UI(Configuration UI)にアクセスできる権限。
サービスの基本設定や接続設定を行うために必要。
✅ TemplateStoreAdmin
権限内容:
テンプレートストアUIにアクセスできる権限。
帳票テンプレート(Adobe LiveCycle Designerで作成したフォーム)の管理が可能。
もしロールを分ける場合は上記を参考に適切にユーザに割り当ててください。


3.xdpファイルを作成する
Adobe LiveCycleDisgnerのソフトを使用して、出力するxdpファイルを作成してます。
CAPサービスで取得したODataの内容を表示させるようにしたいので以下の様なフォーマットにしています。

4.Adobe 提供の SAP Forms サービスのテンプレートストアにxdpファイルをアップロードする
BTPコックピットから
[インスタントおよびサブスクリプション]>[Adobe 提供の SAP Forms サービス]>[アプリケーションに移動]をクリックする

アプリケーションに移動し、この画面が権限エラーなどで表示されない場合は「2.ロールの割り当て」を確認してください!
[Template Store」を押下

テンプレートストアが開いたら3.で作成したxdpファイルをアップロードします

テンプレートストアにあるページ内のスキーマはテンプレート(.xdpファイル)のレイアウトやデータ埋め込み箇所を定義した設計図みたいなものなので任意でアップしてください。

5.認証サービスキーを作成する
BTPコックピットのサブアカウントより、adoberestapiのインスタンスが作成されているので、ここでサービスキーの作成を行います。

6.SAP Business Application StudioからCAPアプリケーションのバックエンドでAdobe Formsサービスを使い、動的なPDF帳票を出力する
APIでうまく取得できない場合は、AdobeFormAPIを試すサイトが以下にあります。
ローカルでAPIを確認するのおすすめです。
・Business Accelerator Hub(アクセストークンの取得等は自動でやってくれます)
https://api.sap.com/api/CF_ADSRestAPI/tryout
SAP BTPのAdobe Formsサービスを利用して、テンプレートストアから取得したテンプレートと動的なXMLデータをマージし、PDFを生成するNode.jsのサンプルコードです。
const axios = require('axios');
/**
* SAP BTP Adobe Formsサービスを利用してPDFを生成する関数
* @returns {Promise<string>} 生成されたPDFのBase64エンコード文字列
*/
async function generatePdfFromTemplate() {
try {
// --- 事前準備 (Prerequisites) ---
// このコードの実行前に、以下の2つの変数が定義されている必要があります。
// ※実際には、これらの値は関数の引数で受け取るか、別の処理で取得します。
// 1. templateString: テンプレートストアから取得したテンプレートのBase64文字列
// 例: const templateString = await getTemplateFromStore('YourTemplateName');
const templateString = '...'; // ここにテンプレートのBase64文字列が入る
// 2. xmlDataString: PDFに埋め込むデータ (XML形式の文字列)
// 例: const xmlDataString = '<root><data><name>Taro Yamada</name></data></root>';
const xmlDataString = '...'; // ここにXMLデータ文字列が入る
const base64XmlData = Buffer.from(xmlDataString).toString('base64');
// --- ステップ1: サービス資格情報と認証トークンの取得 ---
console.log("Fetching service credentials and getting access token...");
// 環境変数 VCAP_SERVICES からAdobe Formsサービスの認証情報を取得
const vcap_services = JSON.parse(process.env.VCAP_SERVICES);
const adsServiceBinding = vcap_services.adsrestapi[0];
const adsCredentials = adsServiceBinding.credentials;
const uaa = adsCredentials.uaa;
// クライアント資格情報フローで認証トークンを取得
const clientId = uaa.clientid;
const clientSecret = uaa.clientsecret;
const tokenUrl = uaa.url + '/oauth/token';
const authHeader = 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
const tokenResponse = await axios({
method: 'post',
url: tokenUrl,
headers: {
'Authorization': authHeader,
'Content-Type': 'application/x-www-form-urlencoded'
},
data: 'grant_type=client_credentials'
});
const accessToken = tokenResponse.data.access_token;
console.log("Access Token obtained successfully.");
// --- ステップ2: PDF生成(レンダリング)APIの呼び出し ---
console.log("Calling PDF Render API...");
// サービス資格情報からレンダリング用のURLを動的に構築
const renderUrl = `${adsCredentials.uri}/v1/adsRender/pdf`;
const pdfResponse = await axios({
method: 'post',
url: renderUrl,
headers: {
'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json',
},
data: {
// (必須) テンプレートストアから取得したテンプレート
"xdpTemplate": templateString,
// (必須) PDFに埋め込むデータ
"xmlData": base64XmlData,
// (任意) PDF生成オプション
"formType": "print", // 印刷用の静的なPDF
"taggedPdf": 1, // タグ付きPDF (アクセシビリティ対応)
"embedFont": 0 // フォントの埋め込み (0: 自動)
}
});
// レスポンスボディの fileContent にPDFのBase64文字列が含まれる
const pdfBase64 = pdfResponse.data.fileContent;
console.log("PDF generated successfully!");
return pdfBase64;
} catch (error) {
// --- エラーハンドリング ---
console.error("An error occurred during PDF generation.");
if (error.response) {
// APIからのエラーレスポンスの場合
console.error(`Status: ${error.response.status}`);
// エラーレスポンスのボディがテキスト形式の場合、内容を表示
const errorData = Buffer.isBuffer(error.response.data)
? error.response.data.toString()
: JSON.stringify(error.response.data);
console.error(`Data: ${errorData}`);
} else {
// その他のエラー (ネットワークエラーなど)
console.error(`Message: ${error.message}`);
}
throw error; // 呼び出し元でさらに処理できるようにエラーを再スロー
}
}
// --- 関数の実行例 ---
// generatePdfFromTemplate()
// .then(pdfBase64 => {
// console.log('Successfully received PDF Base64 string.');
// // ここでpdfBase64を使ってファイル保存などの処理を行う
// })
// .catch(err => {
// console.error('Failed to generate PDF.');
// });
7. アプリケーションから結果を確認する
アプリケーションから見てわかりやすくするために、UI側からのリクエストをトリガーにしてPDFをダウンロードさせる機能も追加してます
DLできたPDFを開いてみます。
Freeのライセンスを使用しているので、帳票の透かしにFreeTierの文字が入っていますが
ODataの動的な値が表示されていることが確認できます。

おわりに
やりました!
これでCAPのバックエンドから自由にPDF帳票を出力する準備が整いました!🎉
今回は、SAP BTPのCAPサービスからAdobe Formsサービスを呼び出して、PDFを動的に生成する方法について解説しました。
サービス間の連携や認証キーは少し複雑ですが、一度仕組みを理解すれば様々な帳票出力に応用できるかと思います。
最後までお読みいただき、ありがとうございました。



