IBM API Connect 関連メモ - (9)z/OS Connect 連携まとめ

# はじめに
オンプレ上のサービスをAPI Connectを用いて公開する際の主な考慮点について整理します。
ここでは、これまでの連載記事で見てきたように、メインフレーム上のサービスをz/OS Connectを使ってAPI化しそれをAPI Connectで公開するというシナリオについて、これまでの記事の内容も踏まえて考察しています。
※ここではメインフレーム+z/OS Connectをバックエンドのサービスプロバイダーとしていますが、メインフレームに限らず他のインフラでも考え方の応用はきくと思います。

## 関連記事

[IBM API Connect 関連メモ - (1)既存REST APIの取り込み](https://qiita.com/tomotagwork/private/d02f8e6092740b0e782f)
[IBM API Connect 関連メモ - (2)API Connectツールキットを使用したNode.jsアプリ作成(Loopback)](https://qiita.com/tomotagwork/private/7872ec8f99de57d7819a)
[IBM API Connect 関連メモ - (3)カタログ、開発者ポータルの構成](https://qiita.com/tomotagwork/private/da577551d7f4c50c4fd2)
[IBM API Connect 関連メモ - (4)各種APIの管理](https://qiita.com/tomotagwork/private/99e9b35227a0f80b2a91)
[IBM API Connect 関連メモ - (5)Secure Gateway経由でのz/OS Connectとの連携](https://qiita.com/tomotagwork/private/59e88b782bb72f1d0c1a)
[IBM API Connect 関連メモ - (6)API Connect-z/OS Connect間TLS接続](https://qiita.com/tomotagwork/private/c70b8566129e51c92423)
[IBM API Connect 関連メモ - (7)z/OS Connect 基本認証 + ID伝播](https://qiita.com/tomotagwork/private/38d41cbc01f92352f649)
[IBM API Connect 関連メモ - (8)z/OS Connect 連携におけるインターフェースの浄化](https://qiita.com/tomotagwork/private/0ec8d2224ad141756510)
[IBM API Connect 関連メモ - (9)z/OS Connect 連携まとめ](https://qiita.com/tomotagwork/private/a9fae53f02773a0c67b1)

# 参考情報
 
z/OS ConnectによるAPI公開の流れについては以下の記事をご参照ください。
 [z/OS Connectによるメインフレーム資産のAPI化　～SoRとSoEを柔軟に連携可能な注目のツールの仕組みと機能](https://www.imagazine.co.jp/z-os-connect%E3%81%AB%E3%82%88%E3%82%8B%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E8%B3%87%E7%94%A3%E3%81%AEapi%E5%8C%96%E3%80%80%EF%BD%9Esor%E3%81%A8soe%E3%82%92%E6%9F%94/)
またAPI設計については以下の記事が参考になると思います。
[現場の事例から学ぶAPI設計の勘所](https://www.imagazine.co.jp/%e7%8f%be%e5%a0%b4%e3%81%ae%e4%ba%8b%e4%be%8b%e3%81%8b%e3%82%89%e5%ad%a6%e3%81%b6api%e8%a8%ad%e8%a8%88%e3%81%ae%e5%8b%98%e6%89%80/)

# API公開での主な考慮点

## 流量制御
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/c8c300ad-7a60-f86f-9856-493255a742b9.png)

社内/社外を問わずAPIを公開する場合、これまで一部のシステムや組織に閉じていた環境に比べるとサービスの利用頻度が高くなることが想定され、その流量制御をどのように行うかは重要になってきます。
各コンポーネントのレベルで流量制御に関してどのようなことが行えるかを整理します。

### z/OS Connect - バックエンドシステム(CICS)間接続での制御
ここはバックエンドの種類によりますが、例えばCICSの場合であればCICS側IPCON定義のRECEIVECOUNT、および、z/OS Connect側zosconnect_cicsIpicConnection エレメントのsendSessions 属性の設定値で並行度の上限が決まります
https://www.ibm.com/support/knowledgecenter/ja/SS4SVW_3.0.0/configuring/ipic_intro.html

もちろんこれに加えてバックエンドシステムそのものでも並行度の設定は行うことになると思います(CICSの場合であれば、SIT:MXT, TranClassでの並行度制御)。

これらはあくまでバックエンドCICSへのリクエスト並行度という位置づけですのでAPI単位での細かな制御というのは行えません。

### z/OS Connect(Liberty)での制御

z/OS Connectとしては流量制御に関する設定が特別用意されているわけではありません。ただ、z/OS Connectランタイムの実体としてはLibertyが使用されていますので、Libertyが持っている機能を利用することが考えられます。例えば、Liberty上の処理はthreadで処理されますのでthread数の上限を設定することである程度の並行度管理はできます。これは、default executorのmaxThreadsで制御できるようです。

参考:
[WebSphere Application Server for z/OS Liberty - Tuning Liberty](https://www.ibm.com/support/knowledgecenter/en/SS7K4U_liberty/com.ibm.websphere.wlp.zseries.doc/ae/twlp_tun.html)
[Why you probably don't need to tune the Open Liberty thread pool](https://openliberty.io/blog/2019/04/03/liberty-threadpool-autotuning.html)

これもz/OS Connect単位での制御ということになりますので、API単位での細かな制御というのは行えません。

<font color="red">※注意
ただし、Libertyのマニュアルとしては以下の記述があるように、executorの設定変更は推奨されているものでは無いようですので利用の際は充分ご注意ください。
</font>

>The Liberty default executor is self-tuning and adapts to the current workload by dynamically adding or removing threads. For most workloads, the executor does not require any tuning, and <font color="red">you are advised not to change any settings of the executor unless you encounter specific problems with thread creation.</font>

### API Connectでの制御

API Connectでは、プランの中でレート制限、および、バースト制限という2種類の制御がAPI単位で行えます。これは単位時間あたりに許容されるリクエスト数を制限するものです(1時点の並行度ではありません)。
以下のようなイメージ条件を複数指定可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/aeffad07-a1ad-a2d1-fccd-84e391713b1a.png)

レート制限とバースト制限の主な違いは以下の通りです。

|   |レート制限  |バースト制限 |
|---|---|---|
|指定可能な単位 |秒、分、時間、日、週 |秒、分  |
|制限に達した場合の挙動  |エラーではじくかログに閾値超えのメッセージを出すか選択(ハード制限の強制チェックボックス) |エラーではじく|
|主な用途 |定常時の流量制限 | スパイク的な高負荷時の流量制限 |

IBM Cloud版のAPI Connectだと流量制御についての設定は上の2つのみです。
ただし、オンプレ版のAPI Connectだと内部的にはDataPower Gatewayが使われておりDataPower Gatewayのレベルでのカスタマイズも可能であるため、並行度の制御なども行えるようです。具体的には、DataPower GatewayではSLM(Service Level Monitor)ポリシーを設定することで制御可能なようです(SLMポリシーのinterval-typeにconcurrentを指定)。
参考:
[Creating an SLM policy](https://www.ibm.com/support/knowledgecenter/en/SS9H2Y_7.7.0/com.ibm.dp.doc/slm_slmpolicy.html)
[SLM policy command - statement](https://www.ibm.com/support/knowledgecenter/ja/SS9H2Y_10.0/com.ibm.dp.doc/statement_slmpolicy.html)



## インターフェースの浄化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/223c5ddc-9014-9af0-34b8-916b7aca8929.png)

APIを公開すると、呼ばれるサービスの利用範囲が広がる訳で、より汎用的なインターフェースである必要があります。とりわけREST APIとして呼ばれるということであれば、サービスの実装は完全に隠蔽されることになりますので、バックエンドのプラットフォームやミドルウェアを意識するようなインターフェースは望ましくありません。
既存のアプリケーションをAPIで公開する場合、既存の仕組みのしがらみに引きずられたインターフェース定義になってしまうことが懸念されますが、できるだけ標準的なAPIとして公開すべきです。ここではそのようなカスタマイズを"インターフェース浄化"と呼んでいます。
インターフェース浄化に向けて各コンポーネントでできることは関連記事の「[IBM API Connect 関連メモ - (8)z/OS Connect 連携におけるインターフェースの浄化](https://qiita.com/tomotagwork/private/0ec8d2224ad141756510)」でを整理していますのでそちらをご参照ください。

## セキュリティ制御
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/37bc64d5-66fa-e4de-2d20-8a75bad7b883.png)

APIはプログラムとプログラムをつなぐ際の境界となるインターフェースです。これを公開するということはバックエンドシステム側からみると接続先のシステムが増えるということになります。その場合新たなセキュリティの要件が生じることになります。特に認証、認可、暗号化の辺りをどうするかの考慮は必要になってくるでしょう。
ただ、バックエンドシステムの世界とフロントエンドシステムの世界では、セキュリティ要件のレベルやポリシーが違ったり、認証のための情報の持ち方が違ったりすることが往々にしてあります。
ここで、API Connectがバックエンドシステムとフロントシステムの間に入ることで、両者の差異をうまく吸収することができます。例えばAPI Connectのレベルで認証/認可の制御は一元管理してそこから後ろのバックエンドのリクエストは特に制限を設けずにリクエストを投げるようにする、あるいは、認可に関する情報はHTTPヘッダーからユーザーデータの一部のフィールド情報として埋め込んでバックエンドと連携する、といったように、柔軟な対応が可能になります(後者はインターフェースの浄化にもつながる話です)。

暗号化と認証についての具体的な構成例については以下の関連記事もご参照ください。
[IBM API Connect 関連メモ - (6)API Connect-z/OS Connect間TLS接続](https://qiita.com/tomotagwork/private/c70b8566129e51c92423)
[IBM API Connect 関連メモ - (7)z/OS Connect 基本認証 + ID伝播](https://qiita.com/tomotagwork/private/38d41cbc01f92352f649)

## フロント側アプリケーションの開発
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/609da34a-4c6e-db79-d339-ef199b8a48f6.png)

Swagger文書などでAPIを明確に定義している場合、そのAPIを境界としてリクエスター側とプロバイダー側の役割分担が明確になることが利点として挙げられます。お互いAPIの仕様にだけ注力すれば相手側の実装は意識する必要はありません。
既存のアプリをサービス化する場合、既存のインターフェースからAPIを定義して公開したとして、実際にリクエスター側のアプリケーションを開発する際は単体テストを行えるスタブ/モックのようなものが必要になります。

z/OS Connect + CICSでスタブを用意する場合、ダミーのCICS-COBOLプログラムを作成してコンパイル/リンクして資源をCICSに登録、そのプログラム呼び出し用にz/OS Connect上にサービス、API定義を登録、というようなことを行う必要があります。
一方、API Connectでは、"アセンブル"をカスタマイズすることでダミーのデータを受け取ってダミーの結果を返す仕組みが実現できます。"アセンブル"の実体としてはyaml定義ファイルですので、コーディングではなくyamlのカスタマイズということになるので比較的容易にスタブ/モックの仕組みを作ることができます。

<details><summary>ダミーのデータを返すスタブ/モック定義例</summary><div>

アセンブルイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/f5ea626e-0079-2ced-3e7a-7122954eb39e.png)


```yaml:ソース抜粋
...
x-ibm-configuration:
  testable: true
  enforced: true
  cors:
    enabled: true
  assembly:
    execute:
      - operation-switch:
          title: operation-switch
          case:
            - operations:
                - verb: get
                  path: /stock
              execute:
                - set-variable:
                    title: stock mock
                    actions:
                      - set: message.body
                        value: '{   "stockCheck": {     "itemList": [{       "itemId": "00000001",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞA001",       "itemPrice": 100000,       "stored": "Y",       "shipFrom": "海浜幕張"     }, {       "itemId": "00000002",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞB001",       "itemPrice": 100000,       "stored": "Y",       "shipFrom": "日本橋箱崎町"     }, {       "itemId": "00000003",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞC001",       "itemPrice": 100000,       "stored": "N",       "shipFrom": "沖縄県名護市辺野古"     }, {       "itemId": "00000004",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞD001",       "itemPrice": 100000,       "stored": "Y",       "shipFrom": "日本橋箱崎町"     }, {       "itemId": "00000005",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞE001",       "itemPrice": 100000,       "stored": "Y",       "shipFrom": "日本橋箱崎町"     }, {       "itemId": "00000006",       "itemName": "ﾜｲﾊﾟｰﾌﾞﾚｰﾄﾞF001",       "itemPrice": 100000,       "stored": "Y",       "shipFrom": "日本橋箱崎町"     }]   } }'
                    version: 1.0.0
            - operations:
                - verb: post
                  path: /order
              execute:
                - set-variable:
                    title: order mock
                    actions:
                      - set: message.body
                        value: '{   "stockOrder": {     "stockOfItemList": [{       "itemId": "00000001",       "stockYN": "Y",       "stockNum": "50"     }, {       "itemId": "00000002",       "stockYN": "N",       "stockNum": "1"     }, {       "itemId": "00000003",       "stockYN": "Y",       "stockNum": "150"     }, {       "itemId": "00000004",       "stockYN": "Y",       "stockNum": "250"     }, {       "itemId": "00000005",       "stockYN": "N",       "stockNum": "2"     }, {       "itemId": "00000006",       "stockYN": "N",       "stockNum": "3"     }]   } }'
                    version: 1.0.0
          otherwise: []
          version: 1.0.0
  phase: realized
...
```

</div></details>

## APIバージョン管理

APIの仕様が変わるというのはすなわちサービスの仕様が変わるということで、それなりに大きな変更と思われます。特にメインフレーム系のアプリケーションはいわゆるSoR(Systems of Record)と呼ばれる部類のものである可能性が高く、フロント側アプリ(いわゆるSoEの部類)に比べてそのライフサイクルは長い傾向にあります。
しかしAPIを公開してエンドユーザーからより直接的にアクセスされる所にさらされるということは、変更に対する要求も受けやすく変更頻度も高くなる可能性も考えられます。

使用するツールに関わらず、API設計そのものとしてバージョン管理をどうするか(パスにバージョン情報を含めるかなど)ということは検討する必要があります。その辺は先に参考として挙げた以下の記事が参考になるでしょう。
参考: [現場の事例から学ぶAPI設計の勘所](https://www.imagazine.co.jp/%e7%8f%be%e5%a0%b4%e3%81%ae%e4%ba%8b%e4%be%8b%e3%81%8b%e3%82%89%e5%ad%a6%e3%81%b6api%e8%a8%ad%e8%a8%88%e3%81%ae%e5%8b%98%e6%89%80/)

API Connectでは、APIが変更された際の置き換えの仕組みを提供してくれています。
以下にも記載していますが、APIのバージョンが変わった場合の反映方法として置換(Replace)と取り替え(Supersede)という2種類が提供されています。
参考: [IBM API Connect 関連メモ - (4)各種APIの管理 - APIのバージョン管理](https://qiita.com/tomotagwork/private/99e9b35227a0f80b2a91#api%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86)

|操作               | 旧バージョンの製品ステータス | 新バージョンの製品ステータス |サブスクリプションのマイグレーション|
|------------------|-------------------------- |--------------------------|-------------------------------|
|置換(Replace)      | 廃棄                      | 公開                     |強制的に自動実行される            |
|取り替え(Supersede)| 非推奨                     | 公開                     |手動で実行する必要あり            |

例えば、"置換"は既存のAPI利用者に影響がない変更、すなわち、Backward Compatibilityのある変更(接続先変更とかオプションフィールドの追加など)の場合にあるタイミングで一気に切り替えるというように使えそうですし、"取り替え"は既存の利用者に影響を与える変更のため新旧バージョンのAPIを並行で有効化しておいて利用者に移行を促す、という使い分けができます。

## API利用実績の分析
流量制御の箇所でも述べましたが、既存のアプリをAPIとして公開すると利用頻度も高くなることが想定されます。フロントが不特定多数の場合その変化の度合いも大きくなりがちで、傾向を把握することもこれまで以上に重要になる可能性があります。

API Connectでは自動でAPI利用状況のデータを収集しており、それを可視化する出来合いのダッシュボードも提供されています(Elasticsearch/Kibanaベース)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132331/25719a4e-91bd-838d-58ee-29eda3cadf8e.png)
APIごとのリクエスト数の推移やレスポンスタイムなどが確認できます。ダッシュボードのカスタマイズも可能です。
このようなデータ収集/可視化の仕組みが組み込まれていて別で構築する必要がないというのは非常にありがたいですね。

## その他

APIを完全に外部に公開して課金対象とする場合にはそのための仕組みも提供されているようです。開発者ポータルもAPI利用者向けに色々とカスタマイズできるようですし。

API Connectを利用するとロジックを追加したりカスタマイズしたりする余地があるというのは各種要件に柔軟に対応できそうです。ある程度のロジックは"アセンブル"で組み込めますし、それに加えてオンプレ版のAPI Connectの場合DataPower Gatewayの部分でカスタマイズできる余地が色々とあるようです。
ただ、あまり複雑なロジックを入れすぎるとパフォーマンスにも影響しますし、メンテナンス性や障害リスクにも影響を及ぼす可能性がありますので、そのあたりのトレードオフは意識して設計する必要がありそうです。