2019年10月11日金曜日

Logic Apps でワークフローのアクション名を列挙する

Logic Apps や Flow を利用していると、時々 JSON 値のキー名がわからない場面に遭遇します。例えば Flow のテンプレート情報や、Logic Apps / Flow のワークフロー定義を参照してあれこれやろうとすると遭遇する問題です。今回、ワークフロー定義をもとにアクション名の列挙を行おうとして、JSON 値のキー名を列挙してみたのでそのやり方をメモしておきます。


Logic Apps や Flow のワークフロー定義は、CodeView や Flow Management コネクタ、または REST API による取得が可能です。その際の取得結果は、大体月のような構造になります。


ワークフロー上のアクションは、definition\actions の値として配列な形で記載されます。この時のキー名はデザイナー上で命名したものが利用されますので、どのようなキー名となるかは固定できません。そのためワークフロー上でこの JSON 値を利用しようとすると、非常に厄介です。今回はこのアクション情報を、1次元の配列に鳴らした形に変換します。

作成した変換用ワークフローの全体図は次のようなものです。

JSON 値のキー名を単純に列挙するのは、Logic Apps の場合 InlineCode コネクタで JavaScript による処理を行うのが、最も楽です。次のコードだけで対応できます。

Object.keys(workflowContext.trigger.outputs.body.actions)

このように Object クラスの Keys メソッドを利用すると、キー名の列挙が行えます。ただし、子要素については列挙されませんので、その部分をどうするかが一番の問題となります。そこで今回は、列挙できたキー名に対してそれぞれ actions という子要素があるかどうかチェック、ある場合は子要素の解析を行うという処理方法を採用しています。

列挙したキー情報を指定して、For Each にてループを作成します。これで各要素に子要素があるかを判断させるようにします。ただし、InlineCode コネクタの処理結果は文字列として連携されてきますので、結果に対して Array 関数で明示的に配列へと変換したうえでループを行う必要があります。

子要素の存在チェックですが、次のような聞き方をしています。

empty(triggerBody()?['actions']?[item()]?['actions'])

最初の HTTP Request トリガに渡されてきた値にある actions、その中に列挙できたキー名でアクセスしてさらに actions という子要素があるかどうか、という聞き方です。真ん中ほどの item() の部分が列挙されたキー名、その後に ? 演算子を付けた形で actions 子要素を参照しに行かせています。? 演算子を利用することで、実際には要素が存在していない場合でも実行時エラーになることを防いでおり、参照できた場合はその値、できなかった場合は空文字列が返却されてきます。そのため empty 関数で「値があるかないか」を判別させ、値がある=子要素がある、値がない=子要素がない、という形で判定を行います。

子要素が存在した場合は、その子要素のキー名を列挙させる必要があります。サンプルのワークフロー定義でいうと、「ダミースコープ」というアクションの中には actions 要素があり、その中で実際に配置された子アクション「エラーとなる計算」が記載されているのがわかると思います。ここは簡単に処理する場合、IF アクションの中でさらに IF アクションで判定させる、とするのですが、Logic Apps や Flow の仕様上だと 8 階層まで深く作ることができてしまいます。そうすると IF を 8 階層組み上げることになるのですが、流石にそれはワークフローとして見づらいものとなります。

このような場合、プログラム開発を行ったことがある人であればお気づきでしょうが、再帰的処理、という方法を採用します。これは自分自身を呼び出す方法で、階層が深い場合には適した手法です。

IF が満たされた場合の処理、すなわち子要素が存在していた場合の処理として、自分自身を呼び出すように HTTP アクションを利用します。こうすることで、別インスタンスとして同じ処理を起動させ、子要素のものからキー名を列挙させることができます。

ここでの戻り値をどう処理するかですが、このワークフローでは最終的に配列な値をそのまま返却するように HTTP Response アクションを設定しています。

そのため再帰的に呼び出した時の結果はそのまま配列変数に追加したいのですが、まとめての追加は Union 関数を利用する必要があるのと、変数の設定アクションでは自分自身を指定することができない(変数 A の設定アクションでは、A の値を利用できない)ため、素直に For Each で処理結果をループさせて追加しています。

試しに Postman でワークフローを呼び出し、結果を確認してみると、ワークフロー定義の情報からアクションを列挙できているのがわかるかと思います。

このようなワークフローをくみ上げると、ワークフロー定義の JSON 情報を渡すことで、アクション情報を列挙することが可能です。これは特定の値だけを抽出して1次元配列に変換する、というパターンですので、色々と応用が利く場面があると思います。

0 件のコメント:

コメントを投稿