投稿者

インターシステムズジャパン
記事 Toshihiko Minamoto · 5月 13 5m read

ObjectScriptを使用したOpenAPI仕様2.0からのIAM構成の自動化

重要である理由

IAMの管理を手動で行うには手間ががかります。OpenAPI(Swagger)仕様を使用して、APIがすでにしっかりとドキュメント化されている場合はなおさらです。 Open API仕様から直接、Kongサービスやルートを自動生成できたらいいのにと思いませんか?

このObjectScriptメソッドはまさにその処理を行います。仕様クラスの XData ブロック内に保管されているOpenAPI 2.0仕様を読み取り、IAM構成を同期するために使用できるdecKと互換性があるYAMLファイルを生成します。

このアプローチは:

  • 手動による構成エラーを削減します
  • ゲートウェイをAPI仕様に常に同期します
  • デプロイメントとオンボーディングを高速化します

前提条件:

  • InterSystems IRIS、またはIRISベースのプラットフォーム
  • InterSystems API Manager
  • Deck CLIツール

メソッドの内容

メソッド ConvertOpenAPIXDataToDeckYAML の機能は次のとおりです。

  1. OpenAPI仕様を読み取る: 指定したクラス内の OpenAPI という名前の XData ブロックから読み取ります。

  2. JSONを解析する:動的オブジェクトに変換します。

  3. エンドポイントを抽出する :HTTPメソッドも抽出します。

  4. YAMLファイルを生成する:生成されたファイルは次を定義します。

    • APIホストとベースパスにポイントしているKongサービス
    • 各エンドポイントのルート
    • 各ルート上のレート制限プラグイン(オプションの拡張機能)

サンプルの仕様クラス

以下のサンプル仕様クラスを使用するか、前回の投稿にリンクされている仕様ファイルを投稿して生成されたクラスを使用できます。

Class MyApp.spec
{
XData OpenAPI [ MimeType = application/json ]
{
{
  "swagger": "2.0",
  "host": "api.example.com",
  "basePath": "/v1",
  "paths": {
    "/users": {
      "get": { "summary": "Get users" },
      "post": { "summary": "Create user" }
    },
    "/products": {
      "get": { "summary": "Get products" }
    }
  }
}
}
}

メソッドと使用

以下はClassMethodです。 もちろんニーズに合わせて調整できます。

/// Convert OpenAPI XData to Deck YAML
ClassMethod ConvertOpenAPIXDataToDeckYAML(specClassName As %String, outputFilePath As %String = "") As %Status
{
    Try {
        // Read the XData block named "OpenAPI"
        Set reader = ##class(%Dictionary.XDataDefinition).%OpenId(specClassName _ "||OpenAPI")
        If reader = "" {
            Write "Error: XData block 'OpenAPI' not found in class ", specClassName, !
            //Quit $$$ERROR
        }
        // Read the stream content into a string
        Set stream = reader.Data
        Set specJSON = ""
        While 'stream.AtEnd {
            Set specJSON = specJSON _ stream.ReadLine()
        }
        // Test call
        //Do ##class(ConsentAPI.Utils).ConvertOpenAPIXDataToDeckYAML("SpecAPI.spec")

        // Parse the JSON into a dynamic object
        Set spec = ##class(%DynamicObject).%FromJSON(specJSON)

        // Initialize YAML structure
        Set deckYAML = "services:" _ $CHAR(13)

        // Extract host and basePath
        Set host = $PIECE($SYSTEM, ":", 1)
        Set basePath = spec.basePath

        // Create service block
        Set deckYAML = deckYAML _ "  - name: " _ host _ $CHAR(13)
        Set deckYAML = deckYAML _ "    url: "_$c(34)_"http://" _ host _ basePath _$c(34)_ $CHAR(13)
        Set deckYAML = deckYAML _ "    routes:" _ $CHAR(13)
        
        // Iterate over paths
        Set pathIter = spec.paths.%GetIterator()
        While pathIter.%GetNext(.key, .value) {
            Set pathKey = key
            Set path = spec.paths.key
            Set routeName = $REPLACE(key , "/", "")
            Set deckYAML = deckYAML _ "      - name: " _ routeName _ $CHAR(13)
            Set deckYAML = deckYAML _ "        strip_path: false"_$CHAR(13)
            Set deckYAML = deckYAML _ "        preserve_host: false"_$CHAR(13)
            Set deckYAML = deckYAML _ "        paths:"_$CHAR(13)
            Set deckYAML = deckYAML _ "          - " _ pathKey _ $CHAR(13)
            Set deckYAML = deckYAML _ "        methods:"_$CHAR(13)
            Set methodIter = value.%GetIterator()
            While methodIter.%GetNext(.key, .value) {
                Set methodKey = key
                Set deckYAML = deckYAML _ "          - " _ $ZCONVERT(methodKey, "U") _ $CHAR(13)

            }
            Set deckYAML = deckYAML _ "        plugins:"_$CHAR(13)
            Set deckYAML = deckYAML _ "        - name: " _ "rate-limiting" _ $CHAR(13)
            Set deckYAML = deckYAML _ "          config:"_$CHAR(13)
            Set deckYAML = deckYAML _ $REPLACE($J("",12),"",$C(32))_"minute: 20" _ $CHAR(13)
            Set deckYAML = deckYAML _ $REPLACE($J("",12),"",$C(32))_"hour: 500" _ $CHAR(13)
        }

        // Output to file or console
        If outputFilePath '= "" {
            Set file = ##class(%Stream.FileCharacter).%New()
            Set file.Filename = outputFilePath
            Do file.Write(deckYAML)
            Do file.%Save()
            Write "YAML saved to: ", outputFilePath, !
        } Else {
            Write deckYAML, !
        }
        //Quit $$$OK
    } Catch ex {
        Write "Error: ", ex.DisplayString(), !
        //Quit ex.AsStatus()
    }
}

メソッドを使用してyamlファイルを生成させるには、ターミナルセッション(IRIS CLI)から呼び出すだけです

Do ##class(MyUtils.APIConverter).ConvertOpenAPIXDataToDeckYAML("MyApp.spec", "/tmp/deck.yaml")

コンソールにyamlを出力することもできます

Do ##class(MyUtils.APIConverter).ConvertOpenAPIXDataToDeckYAML("MyApp.spec")


次のステップ

YAMLファイルが生成されたら、decKを使用してIAMインスタンスに同期できます。

deck gateway sync --workspace deck.yml

これにより、IAM内のサービスおよびルートが仕様に基づいて作成または更新されます。


まとめ

このメソッドは、仕様駆動開発とゲートウェイ構成との間にあるギャップを埋めます。 アーキテクチャ内でInterSystems IRISやHealthShare、IAMを使用するチームにとって最適です。

拡張したいですか?

  • 認証プラグインを含めましょう
  • タグに基づいて複数のサービスを生成しましょう

カスタマイズのサポートが必要な場合は、コメント欄で教えていただくか、気軽にご連絡ください!

元の記事へ さんが書いた @Raef Youssef