API Business HubのSandbox APIをSAP Build Appsで使えるようにするには

## はじめに
最近、SAP Learningで以下のLearning Journeryを受講しました。

https://learning.sap.com/learning-journey/utilize-sap-build-for-low-code-no-code-applications-and-automations-for-citizen-developers

その中でSAP Build AppsからSAP Sales CloudのOData APIを呼び出すという[ハンズオン](https://learning.sap.com/learning-journey/utilize-sap-build-for-low-code-no-code-applications-and-automations-for-citizen-developers/connecting-the-sap-sales-cloud-odata-api-with-sap-build-apps_dd144941-fae7-43d4-a5cb-4bcc95af3d43)があったのですが、指定されたURLが使えなかったためAPI Business Hubの[サンドボックスAPI](https://api.sap.com/api/activity/resource/Appointment)を使用することにしました。

## 課題
API Business HubのAPIを呼ぶには、リクエストヘッダにAPIキーを指定する必要があります。この指定がないとSAP Build Appsで接続設定をしようとしたときにメタデータが取得できず、ODataサービスとして認識されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/fb53706c-076e-49ba-11ca-44ef4a2cf36b.png)

## 解決方法
2023/10/10 追記
Destinationのプロパティ：`URL.headers.APIkey`にAPIキーを設定することが可能です。よってDestinationを使う場合、以下の設定は不要です。
参考：https://blogs.sap.com/2023/10/09/no-code-guide-sap-s-4hana-cloud-to-sap-build-apps-data-visibility/

[API Management](https://help.sap.com/docs/sap-api-management/sap-api-management/what-is-api-management)を使用し、ヘッダにあらかじめAPIキーを設定したものをサービスとして公開します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/aaff2a12-4176-9eab-a1ec-2bdb7bb9f80a.png)

## ステップ
1. API HubからAPI仕様をダウンロード
1. API ManagementでAPI Proxyを登録
1. ポリシーを設定
1. デプロイ

### 1. API HubからAPI仕様をダウンロード
API HubからJSONでAPI仕様をダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/51235c5c-7cdd-0df2-2f49-6794fcb72131.png)

### 2.  API ManagementでAPI Proxyを登録
API ManagementでAPI Proxyを登録します。"Create in API Designer"をクリックします。
※最初"Import API"からやろうとしたところ、ファイルを選択してOKをクリックしても何も起こりませんでした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/dcc75cb2-4e02-7694-9222-935a7530093a.png)
"Import"ボタンからAPI仕様をインポートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/c8ff7919-5d26-e796-7dd6-4bf22c0b4c8f.png)
"Save"で保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/470be1af-3d4b-1d3b-35a3-d05b6bfa914e.png)
任意の名前を指定して保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/827252f3-38ee-58d2-9fc4-b37239384f1d.png)
"Proxy Endpoint"タブで以下の設定を追加します。これはリクエストのメソッドが"OPTIONS"（サーバ側で許可されたリクエストメソッドやリクエストヘッダを調べるリクエスト）の場合、ターゲットに転送しないという意味になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0066dc96-451b-d770-03f8-368d22fb07ba.png)

### 3. ポリシーを設定
"Policies"からポリシーを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/57bf3f58-6d03-630a-7b25-d9e13f369595.png)
ここでは以下のことを行います。
- リクエストヘッダにAPIキーを追加
- レスポンスヘッダにAccess-Control関係の設定を追加（CORS問題を回避するため）
- preflightリクエストの追加

#### 3.1. リクエストヘッダにAPIキーを追加
PreFlowに"Assign Message"のポリシーを置きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/7ccdd161-5570-a592-4e99-11c50f44a2e5.png)
以下のようにポリシーを設定します。

```xml
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
    <Add>
		<Headers>
		         <Header name="APIKey">API Hubで取得したキー</Header>
	    </Headers>     
     </Add>
	<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
	<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
```
#### 3.2. レスポンスヘッダにAccess-Control関係の設定を追加
PostFlowにも"Assgin Message"のポリシーを置きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/eae22b59-5c5e-6157-3b5e-25248a5d7788.png)
以下のようにポリシーを設定します。

```xml
<AssignMessage async="false" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
		 <Set>
		     <Headers>
		         <Header name="Access-Control-Allow-Origin">*</Header>
		         <Header name="Access-Control-Allow-Headers">set-cookie, origin, accept, maxdataserviceversion, x-csrf-token, authorization, dataserviceversion, accept-language, x-http-method, content-type, X-Requested-With, apikey</Header>
		         <Header name="Access-Control-Max-Age">3628800</Header>
		         <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
		         <Header name="Access-Control-Expose-Headers">set-cookie, x-csrf-token, x-http-method</Header>
		     </Headers>
		 </Set>
		 <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
		 <AssignTo createNew="false" type="response">response</AssignTo>
</AssignMessage>
```

#### 3.3. preflightリクエストの追加
"preflight"というProxyEndpointを追加します。設定値は`request.verb == “OPTIONS”`とします。正直なところ何のための設定かわかっていませんが（プリフライトリクエストが飛ぶのか？どのタイミングで？）、参考にした[ブログ](https://blogs.sap.com/2022/07/26/integrate-sap-appgyver-with-sap-integration-suite-consuming-an-integration-flow-levering-sap-api-management-policies/)にあったため入れています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0cbcbb4b-6595-cf6c-79af-2f3acee5ffc7.png)

### 4. デプロイ
設定が完了したらAPI Proxyをデプロイします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/22b79e79-b3f7-aaee-e7f5-dcde2d929547.png)
デプロイされるとProxy URLが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/366103d8-05a9-56d3-3f9e-823fbac10964.png)

ちょっとした注意点として、ここに表示されたリンクをクリックすると**Unable to identify proxy for host**というエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/6aef7fc8-58e6-86e7-e853-ff4578f61732.png)
実は、API Proxy URLとリンクをクリックしたときに開くURLが違っています。リンクをクリックではなく、API Proxy URLをコピーしたものを使用するようにします。
API Proxy URL（正しい）：
`https://f83f5860trial-trial.integrationsuitetrial-apim.us10.hana.ondemand.com:443/f83f5860trial/sap/c4c/odata/v1/c4codataapi`
リンクをクリックしたときに開くURL（正しくない）：
`https://f83f5860trial-trial.integrationsuitetrial-apim.us10.hana.ondemand.com/sap/c4c/odata/v1/c4codataapi/`

以上で、SAP Build AppsからSandbox APIが使えるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0a443ab8-9c86-46ad-de7f-ccccd839582d.png)

## 参考
- [Integrate SAP Build Apps with SAP Integration Suite, consuming an Integration Flow levering SAP API Management policies](https://blogs.sap.com/2022/07/26/integrate-sap-appgyver-with-sap-integration-suite-consuming-an-integration-flow-levering-sap-api-management-policies/)
- [Set header in api managment flow request](https://answers.sap.com/questions/580743/set-header-in-api-managment-flow-request.html)
- [How to Solve CORS Issues with SAP API Management](https://forums.appgyver.com/t/how-to-solve-cors-issues-with-sap-api-management/9752)