[SAP CloudPlatform] MTAプロジェクトのAppRouterについて調べてみた

#はじめに
SAP CloudPlatformのCF環境上でFioriアプリケーション開発をしていると
UIモジュールをデプロイした際、以下のようにインスタンスのでき方が違う場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/660e94d8-f6e7-54ba-f062-f0d9e6580381.png)

画像赤枠で囲んであるApplicationは
どちらも単一のUIモジュールを持つMTAプロジェクトをデプロイして作成したものです。

上記の違いはMTAを作る際、`Use HTML5 Application Repository`オプションにチェックを入れるかどうかで変化します。
下記のチェックが入っているとデプロイ後に`-approuter`がついたApplicationが実行されます。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/16d89ba7-a032-b338-23b9-2970d0a8f5f2.png)

approuter付きのApplicationとそうではないApplicationのなにが違うのか？について
調べてみました。

#AppRouterとは？
結論から言うと、
CF環境に対してUI（HTML5）をデプロイする際の方式は（おそらく）以下の2つあります。

 - AppRouter（HTML5 Application Repository）を使う場合
 - UIモジュールを単一のCFアプリケーションとして実行する場合


AppRouterについては以下が参考になりました。
【参考】
　HTML5 Application RepositoryやAppRouterについては以下のドキュメントを参照
　[SAP Help Portal](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/ja-JP/11d77aa154f64c2e83cc9652a78bb985.html)

　概要的なところは以下のブログにある絵がわかりやすいかもしれません
　※見出し「SCP Applications Building Blocks」のあたりから下のところ
　[Fiori Application Programming Model for Cloud Foundry and ABAP Cloud](https://blogs.sap.com/2018/12/11/programming-applications-in-sap-cloud-platform/)

上記に関してしっかり理解できてはいませんが。。
ざっくりいうとAppRouterを使った構成は以下の3つの機能（サービス）から成り立っているようです。

**HTML5 Application Repository**

 - デプロイされるUIモジュールを`HTML5 Application Repository`というサービスを使って保管・提供できる
 - Repositoryに保管されているコンテンツは`app-runtime service`によって読み取られる 

**HTML5 Application Deployer**

 - `HTML5 Application Repository`に対してアップロードしてくれるアプリケーション
 - SAPが提供するnpmモジュールとのこと
 - コクピットのアプリケーション一覧に追加されるが、デプロイ中のみ起動していて終わると停止する（デプロイだけの役割）

**Application Router – Approuter**

 - 認証やアプリケーションルーティング機能を提供するnode.jsアプリケーション
 - `HTML5 Application Repository`に格納されているHTML5アプリはApprouter経由で実行する
 - xs-app.jsonファイルで定義されているルーティング定義を処理する
 - UAA（認証・承認サービス）が使われる

つまり、
　UIモジュールはDeployerを使ってHTML5 Application Repositoryに格納され、
　実行時にはAppRouter経由でアクセスする
ということらしい？

## AppRouterの利点
上記の参考URLに記載されている通り、利点はいろいろあるようです。
わかりやすいところだと以下があります。

 - 単一のApprouterで複数のHTML5アプリケーションが提供できる
 - SAP Fiori Launchpad(2.0)も（UIモジュール同様）AppRouterに統合される

従来のCFアプリケーションではUIモジュールごとにサーバー側で実行されていたのが統合できる
（CFのリソースも節約できる？）ようです。

#なにが違うのか？

上記で大まかな構成は説明しましたが、
具体的になにが違うのか？を見ていきます。

## プロジェクトの中身
デプロイをした2つのMTAプロジェクトはWebIDE上で以下の通りとなっています。
（`はじめに`の画像参照）
　AppRouter（HTML5 Application Repository）を使用する　　→　HtmlRepoプロジェクト
　AppRouter（HTML5 Application Repository）を使用しない　→　NoHtmlRepoプロジェクト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/4f3cbcb1-bf4b-0a35-4e32-a854f312b8b0.png)

画像の通りフォルダ構成は同じですが、
それぞれのmta.xmlは以下のように差異が出ています。

**mta.xml(HtmlRepo)**

```xml:mta.xml(HtmlRepo)
ID: HtmlRepo
_schema-version: '2.1'
parameters:
  deploy_mode: html5-repo
version: 0.0.1
modules:
  - name: htmlrepo-approuter
    type: approuter.nodejs
    path: htmlrepo-approuter
    parameters:
      disk-quota: 256M
      memory: 256M
    requires:
      - name: HtmlRepo_html5_repo_runtime
      - name: uaa_HtmlRepo
  - name: HtmlRepo_ui_deployer
    type: com.sap.html5.application-content
    path: HtmlRepo_ui_deployer
    requires:
      - name: HtmlRepo_html5_repo_host
    build-parameters:
      requires:
        - name: RepoTestModule
          artifacts:
            - './*'
          target-path: resources/RepoTestModule
  - name: RepoTestModule
    type: html5
    path: RepoTestModule
    build-parameters:
      builder: custom
      commands:
        - npm install
        - npm run build
      supported-platforms: []
      build-result: dist
resources:
  - name: HtmlRepo_html5_repo_runtime
    parameters:
      service-plan: app-runtime
      service: html5-apps-repo
    type: org.cloudfoundry.managed-service
  - name: HtmlRepo_html5_repo_host
    parameters:
      service-plan: app-host
      service: html5-apps-repo
    type: org.cloudfoundry.managed-service
  - name: uaa_HtmlRepo
    parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
    type: org.cloudfoundry.managed-service
  - name: dest_HtmlRepo
    parameters:
      service-plan: lite
      service: destination
    type: org.cloudfoundry.managed-service

```

**mta.xml(NoHtmlRepo)**

```xml:mta.xml(NoHtmlRepo)
ID: NoHtmlRepo
_schema-version: '2.1'
version: 0.0.1

modules:
 - name: NoRepoTestModule
   type: html5
   path: NoRepoTestModule
   parameters:
      disk-quota: 512M
      memory: 256M
   build-parameters:
      builder: grunt
   requires:
    - name: uaa_NoHtmlRepo
    - name: dest_NoHtmlRepo

resources:
 - name: uaa_NoHtmlRepo
   parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
   type: org.cloudfoundry.managed-service

 - name: dest_NoHtmlRepo
   parameters:
      service-plan: lite
      service: destination
   type: org.cloudfoundry.managed-service

```

大きな違いはHtmlRepoプロジェクトの`modules`配下にはUIモジュールのほかに`approuter`と`ui_deployer`が存在するが、
NoHtmlRepoにはUIモジュールのみとなっている点です。

**HtmlRepoプロジェクト**
`approuter`のrequiresにhtml5_repo_runtimeとUaaが含まれており、
`ui_deployer`にはBuildParameter部分にRepositoryにアップロードするモジュールが指定されています。

上記のモジュールがhtml5_repo_runtime、html5_repo_hostを前提としているので、
resourcesに記載が増えています。

※よくわからないのは`dest_HtmlRepo`がresourcesに存在するけれど、requiresに含まれていない点
　デプロイ後のService Instanceも参照アプリケーションがNoneになっているので使われていない？

**NoHtmlRepoのプロジェクト**
UIモジュールのrequiresに直接Uaa、Destinationが指定されています。


> 以下、余談
> 上記でおそらく気にしておかなければならないのは、
> 　・AppRouterが存在する場合はUaaなどの別モジュールやサービスは`approuter`のrequiresに含まれる
> 　・AppRouterが存在しない場合、それらはUIモジュールのrequiresに含まれる
> というところだと思います。

> UIモジュールから同一MTA内（もしくは別MTA）のAPIなどのリソースを読み込もうとした場合、
> AppRouterがいる場合はUIモジュール配下のrequiresに記載しても参照できません。
> [参考QA](https://answers.sap.com/questions/12650707/mta-on-cloud-foundry-with-html5-app-repo-and-appro.html)



## デプロイ後の違い
### HTML5 Application Repositoryを使ったMTA
MTA：HtmlRepoの配下にはRepoTestModuleというUIモジュールが存在します。
これをデプロイして作成されるのが以下のApplicationです。

 - HtmlRepo_ui_deployer
 - htmlrepo-approuter

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/f16b60fe-b1fb-a9d2-638f-18edf5955841.png)

ui_deployerはデプロイ中以外はストップしてます。
デプロイしたSpaceのサービスインスタンスを確認すると、
`HTML5 Application Repository`関連のインスタンスが起動していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/3c11ee06-10ce-d122-efc5-6b52bffe60f7.png)

デプロイされているアプリケーションを実行しようとした場合、
素直にAppRouterのURLを実行してもUIモジュールは実行されません。
`Not Found`になってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/4c4250e8-9404-2064-7dbb-81e48a17d4c6.png)

ApplicationのOverviewに記載されているURLはAppRouterアプリケーションのURLであり、
そこからAppRouterに紐づくRepository（runtime）から自分がアクセスしたいUIを特定するためにパスを追加する必要があります。

参考URLには以下のformatでパスに表示したい画面のキー情報を追加するように記載されています。
**https://\<approuterhost>/\<businessServicePrefix>.\<applicationName-applicationVersion>/\<path to file>**

難しい書き方になっていますが。。。
最低限、アプリケーション名称＋ファイル名がわかれば実行できます。
アプリケーション名称はUIモジュールのComponent.jsから判別可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/c4739646-1ad7-962a-47d6-3b24267ca557.png)

RepoTestModuleのアプリケーション名称は画像赤枠部分なので、
`.`を抜いた`comkyosoRepoRepoTestModule`になります。
ファイル名はとりあえずindex.htmlを実行すればよいので、
**https://\<approuterhost>/comkyosoRepoRepoTestModule/index.html**
(もしくはhttps://\<approuterhost>/comkyosoRepoRepoTestModule-1.0.0/index.html)
で実行可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/e35f9ad1-f715-ad3c-9da0-ac8760e1dde0.png)



### HTML5 Application Repositoryを使っていないMTA
MTA：NoHtmlRepoの配下にはNoRepoTestModuleというUIモジュールが存在します。
これをデプロイして作成されるのが以下のApplicationです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/7bc5d032-0f8d-46e0-e4f0-e2745b8408fa.png)

こちらは素直にアプリケーションのURLでUIモジュールが実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/be35ee19-8f7f-31f1-d57a-fc279d84dc7f.png)

## 複数のUIモジュールが存在した場合にどうなるか？
一つのMTA内にUIモジュールが複数あったとき、
AppRouterを使用する場合と使用しない場合でどう変わるのかを試してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/f702d36c-39de-93b0-0f11-ac15f0b27bc0.png)


上記のように、
HtmlRepoプロジェクト、NoHtmlRepoプロジェクトに`TestModule2`を追加しました。
それぞれのプロジェクトをデプロイすると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/8136ff59-ea59-72be-3dc3-2f505a960558.png)

それぞれのUIモジュールへのURLは以下の通り。

**HtmlRepoプロジェクト**

 - RepoTestModule
   - **https://\<trial>-dev-htmlrepo-approuter.cfapps.eu10.hana.ondemand.com**/comkyosoRepoRepoTestModule/index.html
 - RepoTestModule2
   - **https://\<trial>-dev-htmlrepo-approuter.cfapps.eu10.hana.ondemand.com**/comkyosoRepoRepoTestModule2/index.html
 
**NoHtmlRepoプロジェクト**

 - NoRepoTestModule
   - **https://\<trial>-dev-norepotestmodule.cfapps.eu10.hana.ondemand.com**/NoRepoTestModule/index.html
 - NoRepoTestModule2
   - **https://\<trial>-dev-norepotestmodule<font color="Red">2</font>.cfapps.eu10.hana.ondemand.com**/NoRepoTestModule2/index.html


AppRouterを使った場合は利点として書かれていた通り単一のApprouter（ホスト）内に複数のUIが存在しますが、そうでない場合はUIモジュールとアプリケーションのホストが1:1で存在しています。

AppRouterを利用しない場合はUIモジュールの数だけApplicationが乱立してしまうことになりそうです。

# おわりに

CF環境にFioriアプリケーションをデプロイする場合、
画面が一つしかないという場合であればどちらでもよいですが、
基本的にはHTML5 Application Repository、AppRouterを使うほうがいいです。

ただ、AppRouterなどはおそらく新しいサービスなのでSAP CPのMTAプロジェクトについて困ったときに調べてみるとAppRouterがつかわれていない場合でのトラブルシューティングが多いです。
同一MTA内のODataとUIを連携させたいときなどはmta.xmlのサンプル等がそのまま使えないパターンが多かったので気をつけないといけません。