フロー変数を使用した条件

このページの内容は ApigeeApigee ハイブリッドに該当します。

Apigee Edge のドキュメントを表示する。

条件文は、あらゆるプログラミング言語でよく使用される制御構造です。プログラミング言語と同様、API プロキシ構成では Flow、Policy、Step、RouteRule での条件文をサポートしています。条件文を定義することで、API の動的な動作を定義できます。動的な動作を使用することで、たとえばモバイル デバイスの場合にのみ XML を JSON に変換したり、バックエンド URL をコンテンツ タイプやリクエスト メッセージの HTTP 動詞に基づいてルーティングしたりできます。

このトピックでは、コードを作成することなく、条件を使用して API 管理機能をランタイムに動的に適用する方法を示します。

条件文の構成

条件動作を API プロキシに実装するには条件と変数を組み合わせて使用します。 条件文の作成には Condition 要素を使用します。次の条件は空の状態です。

<Condition></Condition>

条件文を作成するには、次の構文を使用して、条件演算子と変数を追加します。

<Condition>VARIABLE_NAME OPERATOR "VALUE"</Condition>

例:

<Condition>request.verb = "GET"</Condition>

サポートされている条件演算子には、=(等しい)、!=(等しくない)、>(より大きい)があります。読みやすくするために、条件をテキストとして記述することもできます(equalsnotequalsgreaterthan)。

URI パスを操作する場合は、~/ または MatchesPath を使用できます。また、~~ 演算子を使用して JavaRegex 正規表現と照合することもできます。

条件は、バックエンド API リソースに対する API プロキシの条件付き Flow を定義するために使用されます。詳細については、バックエンド API リソースへの条件フローの作成をご覧ください。条件の一覧については、条件リファレンスを参照してください。

変数

条件は、変数の値を評価することでその機能を実行します。変数は、API プロキシによって実行される HTTP トランザクションのプロパティ、または API プロキシ構成自体のプロパティです。API プロキシがアプリからリクエストを受け取るたびに、システム時間、アプリのネットワーク情報、メッセージ上の HTTP ヘッダー、API プロキシ構成、ポリシーの実行などに関連付けられている変数の長いリストが入力されます。これにより、条件文の設定に使用できる豊富なコンテキストが生まれます。

変数には必ずドット表記が使用されます。たとえば、リクエスト メッセージの HTTP ヘッダーは、request.header.HEADER_NAME という変数として使用できます。したがって、Content-type header を評価するには、変数 request.header.Content-type を使用できます。たとえば、request.header.Content-type = "application/json" はリクエストのコンテンツ タイプが JSON である必要があることを示しています。

リクエスト メッセージが GET である場合にのみポリシーが適用される条件文を作成する必要があるとします。リクエストの HTTP 動詞を評価する条件を作成するには、以下の条件文を作成します。この条件の変数は request.verb です。変数の値は GET です。演算子は = です。

<Condition>request.verb = "GET"</Condition>

次も使用できます。

<Condition>request.verb equals "GET"</Condition>

このようなステートメントを使用して条件を評価します。上記の例は、リクエストに関連付けられた HTTP 動詞が GET の場合、true と評価されます。リクエストに関連付けられた HTTP 動詞が POST の場合、この文は false と評価されます。

動的な動作を可能にするには、Flow、Step、RouteRule に Condition を追加します。

Flow に条件を添付する場合は、「条件付き Flow」を作成します。条件付き Flow は、条件が true と評価された場合にのみ実行されます。条件付き Flow には、いくつでもポリシーを追加できます。条件付き Flow を使用すると、特定の条件を満たすリクエスト メッセージやレスポンス メッセージ用に、非常に特殊な処理ルールを作成できます。

たとえば、リクエスト動詞が GET のときにのみ実行されるフローを作成する方法は、以下のとおりです。

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

GET リクエストと POST リクエスト用に 1 つのフローを作成する方法は、以下のとおりです。

<Flows>
  <Flow name="ExecuteForGETs">
    <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
    <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

以下の例に示すように、条件を Policy Step そのものに適用できます。次の Condition により、VerifyApiKey ポリシーはリクエスト メッセージが POST の場合にのみ強制されます。

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

このような条件付き Flow を定義したら、それらにポリシーをアタッチし、API プロキシで GET リクエストには別のポリシーを適用し、POST リクエストには別のポリシーを適用できます。

包括的な情報については、次のリソースをご覧ください。

例 1

以下の例に示されているのは Convert-for-devices という名前の単一の条件付きフローで、ProxyEndpoint のレスポンス フローに構成されています。条件が適用されるエンティティに対し、Condition を要素として追加します。この例では、条件はフローのコンポーネントです。したがって、ステートメントが true と評価されるたびにこのフローが実行されます。

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

アプリから受信したリクエストごとに、Apigee はすべての HTTP ヘッダーの値を変数として格納します。リクエストに User-Agent という HTTP ヘッダーが含まれている場合、そのヘッダーと値は request.header.User-Agent という変数として格納されます。

上記の ProxyEndpoint 構成が指定されると、Apigee は request.header.User-Agent 変数の値をチェックし、条件が true と評価されるかどうかを確認します。

条件が true と評価された場合、つまり変数 request.header.User-Agent の値が Mozilla と等しい場合は、条件 Flow が実行され、ConvertToJSON という XMLtoJSON ポリシーが適用されます。true ではなかった場合、Flow は実行されず、XML レスポンスは変更されずに(XML 形式で)リクエスト元のアプリに返されます。

例 2

モバイル デバイスの場合に限ってレスポンス メッセージを XML から JSON に変換する必要がある、という具体的な例を考えてみましょう。まず、Weather API からの XML 形式のレスポンスを JSON に変換するポリシーを作成します。

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

上記のポリシー構成は API プロキシに対して、レスポンス メッセージを取得し、デフォルト設定で XML から JSON へ変換し、その結果を新しいレスポンス メッセージに書き出すよう指示します(リクエスト メッセージを XML から JSON に変換する場合は、両方の値を request に設定します)。

レスポンスを XML から JSON に変換するには、変換を実行する条件付きレスポンス Flow を構成する必要があります。たとえば、すべてのレスポンスを XML から JSON に変換してからクライアント アプリに返すには、次の ProxyEndpoint レスポンス Flow を構成します。

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

標準のリクエストを使用して API を呼び出すと、レスポンスは JSON 形式になります。

ここで、目指している動作は要求側クライアントがモバイル デバイスの場合に限って Weather レポートを JSON に変換することです。このような動的な動作を実現するには、Flow に条件文を追加する必要があります。

条件フローをテストする

このサンプル リクエストでは、HTTP User-Agent ヘッダーが Mozilla に設定され、条件文が true と評価され、条件付きフロー Convert-for-devices が実行されます。

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282

Python を利用できる場合にプリティ プリントするには、以下のようにします。

curl -H "User-Agent:Mozilla" http://example.com/weather/forecastrss?w=12797282 | python -mjson.tool

レスポンスの例

. . .

"yweather_forecast": [
   {
      "code": "11",
      "date": "12 Dec 2012",
      "day": "Wed",
      "high": "55",
      "low": "36",
      "text": "Showers"
    },
    {
      "code": "32",
      "date": "13 Dec 2012",
      "day": "Thu",
      "high": "56",
      "low": "38",
      "text": "Sunny"
    }
  ]
}

. . .

User-Agent ヘッダーなしで送信されたリクエスト、または Mozilla とは異なる値を持つリクエストは、XML 形式のレスポンスになります。

$ curl http://example.com/weather/forecastrss?w=12797282

変更なしの XML レスポンスが返されます。

レスポンスの例

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

パターン マッチング

このセクションでは、Apigee フローの条件でパターン マッチングを使用する方法について説明します。

演算子

このセクションでは、条件文で次のパターンマッチ演算子を使用する方法について説明します。

一致

まず、Matches 条件演算子または ~ 条件演算子を見てみましょう。この 2 つの演算子は同じものですが、英単語の形である Matches のほうが読みやすいと考えられます。

概要: Matches 演算子には 2 つの種類があります。文字列をそのまま照合するか、* でワイルドカード照合を行います。ご想像のとおり、ワイルドカードは 0 字以上の文字と一致します。詳細を見てみましょう。

次の XML は、Step 条件を示します。条件が true と評価されると、SomePolicy ポリシーが実行されます。この例では、変数 proxy.pathsuffix(リクエストのパス接尾辞を格納する Apigee の組み込み変数)をテストします。ただし、文字列を含むすべてのフロー変数の値をテストできます。したがって、受信リクエストのベースパスが /animals でリクエストが /animals/cat の場合、パス接尾辞はリテラル文字列 /cat になります。

<PreFlow name="PreFlow">
  <Request>
    <Step>
      <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
      <Name>SomePolicy</Name>
    </Step>
  </Request>
  <Response/>
</PreFlow>

質問: SomePolicy の実行を引き起こすプロキシのパス接尾辞は何ですか?可能性は 1 つしかありません。

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい、実行されます。プロキシのパス接尾辞が /cat と完全に一致するためです。接尾辞が /bat/dog、または / などの場合、実行されません。

ここで、ワイルドカード文字 * を使用する次の条件文について考えてみましょう。

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい。ワイルドカードは任意の文字と一致し、「"/cat」が一致します。

API 呼び出し:

GET http://example.com/matchtest/bat

ポリシーは実行されるでしょうか?はい。ワイルドカードは任意の文字と一致するため、"/bat" が一致します。

API 呼び出し:

GET http://example.com/matchtest/owl

ポリシーは実行されるでしょうか?いいえ。ワイルドカードは o と一致しますが、文字 wl には一致しません。

では、ワイルドカードを接尾辞の末尾に移動してみましょう。

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい。ワイルドカードは、あらゆる文字の 0 字以上と一致するためです。

API 呼び出し:

GET http://example.com/matchtest/bat

ポリシーは実行されるでしょうか?いいえ、/bat は一致しません。

API 呼び出し:

GET http://example.com/matchtest/cat123

ポリシーは実行されるでしょうか?はい。ワイルドカードは、あらゆる文字の 0 文字以上と一致するため、123 が一致します。

API 呼び出し:

GET http://example.com/matchtest/cat/bird/mouse

ポリシーは実行されるでしょうか?はい。ワイルドカードは、あらゆる文字の 0 文字以上と一致するため、/bird/mouse が一致します。このような式は、リテラル文字の後のすべてに一致するため、問題を引き起こす可能性があります。

質問: Matches 演算子では大文字と小文字が区別されますか?

はい。次のような条件があるとします。

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?いいえ。ワイルドカードは(大文字と小文字に関係なく)すべての文字と一致しますが、小文字の aA とは一致しません。

API 呼び出し:

GET http://example.com/matchtest/bAt

ポリシーは実行されるでしょうか?はい、大文字と小文字が一致しています。

質問: Matches 演算子で、文字をエスケープするにはどうすればよいですか?

予約済みの文字をエスケープするには、パーセント % を使用します。例:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?いいえ。Matches 演算子はリテラル文字列 c*at を探します。

API 呼び出し:

GET http://example.com/matchtest/c*at

質問: ポリシーは実行されるでしょうか?

はい。このパスはちょっと一般的には見られませんが、一致します。

JavaRegex

ご覧のとおり、単純な状況には Matches 演算子が適しています。ただし、別の演算子(JavaRegex または ~~)演算子を使用することもできます。この 2 つは同じ演算子ですが、JavaRegex の方が読みやすくなっています。JavaRegex と呼ばれるのは、正規表現パターン マッチングが可能なためです。Apigee は Java 言語の java.util.regex パッケージ内のクラスと同じルールに従います。JavaRegex 演算子の動作は Matches 演算子と大きく異なるため、この 2 つを混同しないことが重要です。

概要: JavaRegex 演算子を使用すると、条件文で正規表現構文を使用できます。

次のコードは、Step 条件を示します。条件が true と評価された場合、SomePolicy ポリシーが実行されます。この例では、変数 proxy.pathsuffix(リクエストのパス接尾辞を格納する Apigee の組み込み変数)をテストします。受信リクエストのベースパスが /animals でリクエストが /animals/cat の場合、パス接尾辞はリテラル文字列 /cat です。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

質問: SomePolicy の実行を引き起こすプロキシのパス接尾辞は何ですか?Matches 演算子と同様、この場合、考えられる選択肢は 1 つしかありません。

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい、実行されます。プロキシのパス接尾辞が /cat と完全に一致するためです。接尾辞が /bat または /dog などの場合、実行されません。

ここで、* 数量子を使用して正規表現を作成してみましょう。この数量子は、直前の文字の 0 個以上の文字と一致します。

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?いいえ。* 数量子は、先行する文字(ここでは c)が 0 または 1 回出現する場合に一致します。

API 呼び出し:

GET http://example.com/matchtest/ccccct

ポリシーは実行されるでしょうか?はい。ワイルドカードは、先行する 0 個以上の文字と一致するためです。

次に、? 数量子を使用します。これは、先行する文字と 1 回一致するか、まったく一致しません。

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい。? 数量子は、先行する文字(ここでは a)の 0 または 1 回出現する場合に一致します。

API 呼び出し:

GET http://example.com/matchtest/ct

ポリシーは実行されるでしょうか?はい。? 数量子は、先行する文字の 1 個と一致する、どれとも一致しません。この場合、a 文字がないため、条件は true と評価されます。

API 呼び出し:

GET http://example.com/matchtest/caat

ポリシーは実行されるでしょうか?いいえ。? 数量子は、先行する文字(ここでは a)の 1 個と一致します。

次に、[abc] またはグループ化形式の正規表現を使用します。これは、文字 abc と一致します。

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい。ここでは正規表現を使用しており、[cbr] 式は cb、または r と一致します。以下の呼び出しも一致します。

GET http://example.com/matchtest/bat

GET http://example.com/matchtest/rat

しかし、次は一致しません。

GET http://example.com/matchtest/mat

質問: JavaRegex 演算子では大文字と小文字が区別されますか?

はい。次のような条件があるとします。

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat

ポリシーは実行されるでしょうか?はい。この正規表現は、先行する文字(ここでは a)は 0 または 1 回出現する場合に一致します。

API 呼び出し:

GET http://example.com/matchtest/cAt

質問: ポリシーは実行されるでしょうか?

いいえ。大文字 A が小文字 a と一致しません。

MatchesPath

MatchesPath 演算子は、この ~/ のように指定できます。これは、Matches~)演算子と JavaRegex(~~)演算子に少し似ています。ただし、MatchesPath は完全に異なります。

この演算子は、パスをパーツの連続と考えることに注意してください。そのため、パスが /animals/cats/wild であれば、/animals/cats/wild の各部で構成されるパスと考えることができます。

MatchesPath 演算子では、シングル アスタリスク(*)とダブル アスタリスク(**)の 2 つのワイルドカード表記を使用できます。シングル アスタリスクは 1 つのパス要素と一致します。ダブル アスタリスクは 1 つまたは複数のパス要素と一致します。

例を見てみましょう。この例では、変数 proxy.pathsuffix(リクエストのパス接尾辞を格納する Apigee の組み込み変数)をテストします。ただし、文字列を含むすべてのフロー変数の値をテストできます。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

質問: SomePolicy の実行を引き起こすプロキシのパス接尾辞は何ですか?

API 呼び出し:

GET http://example.com/matchtest/animals

質問: ポリシーは実行されるでしょうか?

いいえ。/* により指定されているとおり、/animals の後に別のパス要素が必要です。

API 呼び出し:

GET http://example.com/matchtest/animals/

ポリシーは実行されるでしょうか?はい。このパスには別のパス要素(/animals/ の後の部分)がありますが、中身が空です。

API 呼び出し:

GET http://example.com/matchtest/animals/cats

ポリシーは実行されるでしょうか?はい。このパスには、/animals の後に要素(/cats)が明確に配置されています。

API 呼び出し:

GET http://example.com/matchtest/animals/cats/wild

質問: ポリシーは実行されるでしょうか?

いいえ。シングル アスタリスクの場合 1 つのパス要素にのみ一致しますが、この API では /animals の後に複数の要素が存在します。

では、ダブル アスタリスクを使ってみましょう。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

質問: SomePolicy の実行を引き起こすプロキシのパス接尾辞は何ですか?

API 呼び出し:

GET http://example.com/matchtest/animals

ポリシーは実行されるでしょうか?いいえ。/** で指定された次のパス要素が 1 つ以上必要です。

API 呼び出し:

GET http://example.com/matchtest/animals/

ポリシーは実行されるでしょうか?

はい。このパスには別のパス要素(/animals/ の後の部分)がありますが、中身が空です。

API 呼び出し:

GET http://example.com/matchtest/animals/cats

ポリシーは実行されるでしょうか?

はい。このパスには、/animals の後に少なくとも 1 つの要素があります。

API 呼び出し:

GET http://example.com/matchtest/animals/cats/wild

ポリシーは実行されるでしょうか?

はい。このパスには、/animals の後に複数の要素があります。

アスタリスクを組み合わせる

1 つのアスタリスク(*)と 2 つのアスタリスク(**)を組み合わせて、パスマッチングをさらにきめ細かく指定できます。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

API 呼び出し:

次の API 呼び出しは、すべて一致します。

GET http://example.com/matchtest/animals/cats/wild/

および

GET http://example.com/matchtest/animals/dogs/wild/austrailian

および

GET http://example.com/matchtest/animals/birds/wild/american/finches

API リソース

RESTful サービスは、API リソースを集めたものです。API リソースは、デベロッパーが API を呼び出すことでアクセスできるエンティティを識別する URI パス フラグメントです。たとえば、サービスによって気象レポートと天気予報を提供している場合、バックエンド サービスで次の 2 つの API リソースが定義されます。

  • http://mygreatweatherforecast.com/reports
  • http://mygreatweatherforecast.com/forecasts

API プロキシを作成する場合は(初めての API プロキシの作成を参照)、少なくともバックエンド サービスにマッピングするエイリアスのベース URL を作成することになります。例:

バックエンドのベース URL 新規または同等の API プロキシの URL
http://mygreatweatherforecast.com http://example.com/mygreatweatherforecast

この時点で、どちらかのベース URL を使用して、バックエンドへの API 呼び出しを行うことができます。しかし、API プロキシの URL を使用するともっと興味深い処理を行うことができます。

API プロキシを使用すると Apigee が収集を開始する API アナリティクスに加えて、プロキシでは、バックエンドのリソースにマッピングする条件付きフローも定義できます。基本的に、GET 呼び出しが /reports リソースに到着すると、Apigee はなんらかの処理を行う必要があります。

次の図は、最終的に同じバックエンドにアクセスする 2 つの URL の動作の違いを示しています。1 つはプロキシを使用しないリソース URL で、もう 1 つは同じバックエンド リソースへの条件付きフローを使用する Apigee API プロキシです。条件付きフローについては、以下で詳しく説明します。

条件付きフローを含む Apigee API プロキシの URL の場合、レスポンスは XML を JSON に変換して分析を収集します。

API プロキシが特定のバックエンド リソースにマッピングされる仕組み

API プロキシの URL をバックエンド サービスのベース URL にマッピングすると(プロキシの作成時に)、先ほど説明した /reports リソースや /forecasts リソースなどの特定のリソースに条件付きフローを追加できます。

たとえば、呼び出しが /reports リソースまたは /forecasts リソースに到着したら、Apigee に「何かをさせたかった」とします。この時点では、Apigee が何をすべきかを指示するのではなく、これらのリソースに対する呼び出しをリッスンする必要があることを指示しているにすぎません。これは、条件を使用して行います。Apigee API プロキシでは、/reports/forecasts 用の条件付きフローを作成できます。概念としては、次の API プロキシの XML で、どのような条件になるかを示します。

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

これらの条件では、URL に GET リクエストが URL の /reports/forecasts に到着すると、これらのフローにアタッチしたポリシーを通じて、API 開発者が指示したとおりに処理が行われます。

次に、条件が満たされたときに行う処理を Apigee に指示する例を紹介します。次の API プロキシの XML では、GET リクエストが https://example.com/mygreatweatherforecast/reports に送信されると、Apigee がレスポンスで XML-to-JSON-1 ポリシーを実行します。

<Flows>
  <Flow name="reports">
    <Description/>
    <Request/>
    <Response>
      <Step>
        <Name>XML-to-JSON-1</Name>
      </Step>
    </Response>
  <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

これらのオプションの条件付きフローに加えて、各 API プロキシにはデフォルトのフローが 2 つあります。1 つは条件付きフローの前に実行される <PreFlow>、もう 1 つは条件付きフローの後に実行される <PostFlow> です。これらは、API プロキシに対して任意の呼び出しが行われたときにポリシーを実行するのに役立ちます。たとえば、アクセスされるバックエンド リソースに関係なく、すべての呼び出しでアプリの API キーを検証する場合は、Verify API Key ポリシーを <PreFlow> に配置します。フローの詳細については、フローの構成をご覧ください。

バックエンド リソースに対する条件付きフローを作成する

API プロキシでバックエンド リソースへの条件付きフローを定義することは完全に任意選択です。ただし、条件付きフローを使用すると、細かい管理とモニタリングを適用できます。

できること

  • API モデルのセマンティクスを反映する方法での管理を適用する
  • 個々のリソースパス(URI)にポリシーとスクリプト動作を適用する
  • 分析サービス向けの細かな指標を収集する

たとえば、バックエンドの /developers リソースから /apps リソースに対してさまざまな種類のロジックを適用する必要があるとします。

このためには、API プロキシで、/developers および /apps の 2 つの条件付きフローを追加します。

新しいプロキシ エディタ

条件フローを追加するには:

  1. プロキシ エディタの [Develop] タブを選択します。
  2. 左側のペインで、[Proxy endpoints] > [default] を選択します。

    左側のペインで、[Proxy endpoints] > [default] を選択します。

  3. [Response] ペインの上にある [+] ボタンをクリックします。

    条件付きフローの追加ボタン

  4. [Add Conditional Flow] ダイアログで次の構成を入力します。
    • フロー名: Developers
    • 条件タイプ: Path
    • パス: /developers

    [Add conditional flow] ダイアログ。

    URI の末尾が /developers の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。

  5. 次に、/apps 用の条件付きフローを追加し、リクエストの URI と POST 動詞の両方で条件をトリガーしたいと想定します。この構成には、以下の設定が含まれます。
    • フロー名: Apps
    • 条件タイプ: Path and Verb
    • パス: /apps
    • 動詞: POST

    URI の末尾が /apps で、動詞が POST の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。

追加されたフローは [Response] ペインに表示されます。

[Add conditional flow] ダイアログ。

従来バージョンのプロキシ エディタ

API プロキシ エディタの [Navigator] ペインの [Develop] ペインで、[Proxy Endpoints] の [default] の隣の をクリックします。

デフォルトの横にあるプラス記号の上にポインタを置くと、ポップアップ テキストに「New Flow」と表示されます。

[New Conditional Flow] ウィンドウで、次のキー構成を入力します。

  • フロー名: Developers
  • 条件タイプ: Path
  • パス: /developers

[New Conditional Flow] ペインで、「Developers」という名前のフローに「App developers registered with Developer Services」という説明が付いている。

URI の末尾が /developers の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。

次に、/apps 用の条件付きフローを追加し、リクエストの URI と POST 動詞の両方で条件をトリガーしたいと想定します。この構成には、次の設定が含まれます。

  • フロー名: Apps
  • 条件タイプ: Path and Verb
  • パス: /apps
  • 動詞: POST

[New Conditional Flow] ペインで、「Apps」というフローに「Developer apps registered in Developer Services」という説明が付いています。

URI の末尾が /apps で、動詞が POST の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。

[Navigator] ペインに、[Apps] と [Developers] の新しいフローが表示されます。

[Navigator] ペインの [Proxy Endpoints] に、Apps と Developers の新しいフローが表示されている。

いずれかのフローを選択して、API プロキシ エディタのコードビューで条件付きフロー構成を表示します。

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

ご覧のとおり、API リソースは受信リクエストの URI パスを評価する単なる条件付き Flow です(proxy.pathsuffix 変数は、ProxyEndpoint 構成で構成されている BasePath に続くリクエストの URI を識別します)。

定義した各 API リソースは、API プロキシの条件付きフローによって実装されます(フローの構成をご覧ください)。

API プロキシをテスト環境にデプロイすると、

http://example.com/PROXY_PATH/apps

上記のリクエストによって条件が true と評価され、このフローと関連付けられているポリシーが実行されます。

次の例の条件では、Java 正規表現を使用して、末尾にスラッシュがあるもの(/apps または /apps/**)の有無に関係なく、/apps リソースへの呼び出しを識別します。

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

このタイプの条件の詳細については、Apigee コミュニティ末尾に「/」が含まれているかどうかに関係なく照合する方法をご覧ください。

階層 URI のモデル化

階層的 API のリソースがある場合もあります。たとえば、デベロッパー アプリ リスト API は、デベロッパーに帰属するすべてのアプリを一覧表示する方法を提供します。URI パスは次のとおりです。

/developers/DEVELOPER_EMAIL/apps

コレクションの各エンティティに対して一意の ID が生成されるリソースを使用している場合があり、これには、次のようなアノテーションが付けられることがあります。

/genus/:id/species

このパスは、次の 2 つの URI に同様に適用されます。

/genus/18904/species
/genus/17908/species

API リソースでこの構造を表すためには、ワイルドカードを使用できます。例:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

これにより、API のリソースとして階層 URI が適切に解決されます。

特に API の階層が深い場合、特定の URI フラグメント以下のすべての要素を解決することが必要になる可能性があります。このためには、リソース定義にワイルドカード(アスタリスク 2 個)を使用します。たとえば、次の API リソースを定義する場合、

/developers/**

この API リソースは、次の URI パスを解決します。

/developers/DEVELOPER_EMAIL/apps
/developers/DEVELOPER_EMAIL/keys
/developers/DEVELOPER_EMAIL/apps/APP_ID/keys

次に、条件付きフロー条件が API プロキシの定義ではどのように指定されるかを示します。

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

その他の例

RouteRule に添付された条件

<RouteRule name="default">
  <!--this routing executes if the header indicates that this is an XML call. If true, the
    call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

ポリシーに添付された条件

<Step>
  <!--the policy MaintenancePolicy only executes if the response status code is exactly 503 -->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

条件付きフロー

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

条件における演算子の例

条件の作成に使用する演算子の例は、次のとおりです。

  • request.header.content-type = text/xml
  • request.header.content-length < 4096 && request.verb = PUT
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath /*/statuses/**
  • request.queryparam.q0 NotEquals 10

実用的な例: パスの末尾の / を無視

Apigee デベロッパーは通常、これらのパス接尾辞(/cat/cat/)の両方を処理したいと考えています。これは、一部のユーザーやクライアントがパスの末尾にスラッシュを追加して API を呼び出し、条件文でそれを処理する必要があるからです。この正確なユースケースについては、末尾に「/」が含まれているかどうかに関係なく照合する方法で説明します。

必要に応じて、次のように正規表現を使用せずに行うことができます。

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

これは有効な選択肢であり、読みやすく明確です。

ただし、次のように、正規表現を使用して同じことができます。文の正規表現部分をグループ化するために括弧が使用されていますが、必須ではありません。

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

API 呼び出し:

GET http://example.com/matchtest/cat
or
GET http://example.com/matchtest/cat/

ポリシーは実行されるでしょうか?はい。正規表現で ? 文字を使用した場合は、先行する文字が 0 または 1 回出現する場合に一致します。したがって、/cat/cat/ の両方が一致します。

API 呼び出し:

GET http://example.com/matchtest/cat/spotted

ポリシーは実行されるでしょうか?いいえ。正規表現は、先行する文字が 0 または 1 回出現する場合に一致し、これ以外は許容されません。

JavaRegex を使用して任意の文字列を照合する

このトピックのすべての例で、組み込みのフロー変数 proxy.pathsuffix の照合方法を示します。任意の文字列またはフロー変数に対して、proxy.pathsuffix のような組み込みフロー変数か否かに関係なく、パターン マッチングを実行できます。

たとえば、任意の文字列(バックエンド ペイロードで返された文字列や認証サーバー検索から返された文字列など)をテストする条件がある場合に、マッチング演算子を使用してテストできます。JavaRegex を使用すると、正規表現は件名の文字列全体と比較されます。件名が abc で正規表現が [a-z] の場合、[a-z]1 つの英字と完全に一致するため、一致は認められません。式 [a-z]+[a-z]*[a-z]{3} と同様に機能します。

具体的な例を見てみましょう。認証サーバーがロールのリストをカンマ区切り文字列 editor, author, guest として返します。

editor は文字列全体の一部にすぎないため、以下の構成では、編集者のロールの有無を検証できません。

<Condition>returned_roles ~~ "editor"</Condition>

ただし、次の構成は機能します。

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

これは、.* 接頭辞と接尾辞によって、単語の区切りと文字列のその他の部分が考慮されるためです。

この例では、Matches 演算子を使用して editor を検証することもできます。

<Condition>returned_roles ~~ "*editor*")</Condition>

ただし、より高い精度が必要な場合は、JavaRegex を使用する方が適切です。

JavaRegex 式で二重引用符をエスケープする

Condition 構文では、JavaRegex 式を二重引用符で囲む必要があります。したがって、二重引用符を含む正規表現を使用する場合、照合するには別の方法が必要になります。その方法とは「Unicode」です。たとえば、次のような二重引用符を含むヘッダーを渡すとします。

 -H 'content-type:multipart/related; type="application/xop+xml"'

正規表現でこのヘッダーを照合しようとすると、式に二重引用符が含まれているため、Invalid Condition エラーが発生します。

request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"

この問題の解決策は、ASCII ベースの二重引用符を、対応する Unicode の \u0022 に置き換えることです。たとえば、次の式は有効であり、期待される結果となります。

request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"