フロー変数での条件

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

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

条件文の構成

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

    <Condition></Condition>
    

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

    <Condition>{variable.name}{operator}{"value"}</Condition>
    

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

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

条件は、バックエンド API リソースに対する API プロキシ条件フローを定義するのに使用します。これについては、バックエンド API リソースへの条件フローのマップで説明しています。条件の完全なリストについては、条件リファレンスをご覧ください。

変数

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

変数には必ずドット表記が使用されます。たとえば、リクエスト メッセージ上の HTTP ヘッダーは、request.header.{header_name} という変数として使用できます。したがって、Content-type ヘッダーの評価には、変数 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>
    

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

動的な動作を実現にするには、Condition を Flow、Step、RouteRule に添付します。

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

たとえば、リクエスト動詞が GET の場合にのみ実行される Flow は、以下のように作成します。

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

Flow を GET 用に 1 つ、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 Policy はリクエスト メッセージが POST の場合にのみ強制されます。

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

このような条件 Flow を定義したら、そこに Policy を添付して、API プロキシで GET リクエストにはあるポリシーの一式、POST リクエストには別のポリシーの一式を強制するようにできます。

全体的なリファレンス情報については、次のリソースをご覧ください。

例 1

次の例は、ProxyEndpoint レスポンス フローに構成された、Convert-for-devices という単一の条件フローを示しています。条件が適用されるエンティティに対し、Condition を要素として追加します。この例において、条件はこのフローの構成要素の 1 つです。したがって、このフローは、この文が true と評価された場合には常に実行されます。

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

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

上記の ProxyEndpoint 構成が指定されると、Edge では、request.header.User-Agent 変数の値を調べて、条件が true と評価されるかどうかを確認します。

条件が true と評価される(つまり、変数 request.header.User-Agent の値が Mozilla と等しい)場合、条件付きフローが実行され、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://{org_name}-test.apigee.net/weather/forecastrss?w=12797282
    

Python を利用できる場合に pretty print するには、以下のようにします。

    $ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/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://{org_name}-test.apigee.net/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

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

まとめ: 「Matches」演算子では、2 つの方法があります。文字列をそのまま照合するか、「*」によるワイルドカード照合を行うかです。ワイルドカードは 0 字以上の文字と一致します。それでは、その動作を見てみましょう。

次の XML は、Step 条件を示します。条件が true と評価された場合、SomePolicy ポリシーが実行されます。この例では、変数 proxy.pathsuffix(リクエストのパス接尾辞を格納する Edge の組み込み変数)をテストします。ただし、文字列を含む任意のフロー変数の値をテストできることに注意してください。したがって、この例で、受信リクエストのベースパスが /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://artomatic-test.apigee.net/matchtest/cat

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/bat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/owl

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/bat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat123

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat/bird/mouse

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

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/bAt

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

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/c*at

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

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

JavaRegex

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

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

次のコードは、Step 条件を示します。条件が true と評価された場合、SomePolicy ポリシーが実行されます。この例では、変数 proxy.pathsuffix(リクエストのパス接尾辞を格納する Edge の組み込み変数)をテストします。受信リクエストのベースパスが /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://artomatic-test.apigee.net/matchtest/cat

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

ポリシーは実行されるでしょうか?いいえ。「*」数量子は、先行する文字(ここでは "c")の 0 字以上と一致します。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/ccccct

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/ct

ポリシーは実行されるでしょうか?はい。「?」数量子は、先行する文字の 0 字か 1 字と一致します。この場合は、"a" という文字は存在しないため、条件は true と評価されます。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/caat

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

次に、"[abc]"(グループ化)スタイルの正規表現を使用してみましょう。これは、文字 "a"、"b"、"c" と一致します。

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

GET http://artomatic-test.apigee.net/matchtest/bat

GET http://artomatic-test.apigee.net/matchtest/rat

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

GET http://artomatic-test.apigee.net/matchtest/mat

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cAt

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

いいえ。大文字の "A" が小文字の "a" と一致しないためです。

MatchesPath

MatchesPath 演算子は、この「~/」のように指定することもできます。外観上は、Matches(~)や JavaRegex(~~)演算子にも少し似ています。しかし、MatchesPath はまったく異なります。

この演算子は、パスを一連の部分の組み合わせとして確認します。そのため、パスが /animals/cats/wild の場合は、パスを部分 "/animals"、"/cats"、"/wild" で構成されていると考えることができます。

MatchesPath 演算子では、2 種類のワイルドカード表記(1 つのアスタリスク(*)と 2 つのアスタリスク(**))を使用できます。アスタリスクが 1 つの場合、1 つのパス要素と一致します。アスタリスクが 2 つの場合、1 つ以上のパス要素と一致します。

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

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals

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

いいえ。条件で「/*」によって指定されているように、"/animals" の後ろに別のパス要素が必要であるためです。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals/

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

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

いいえ。アスタリスクが 1 つの場合、1 つのパス要素とのみ一致しますが、この API では、"/animals" の後ろに複数の要素が存在するためです。

次に、2 つのアスタリスクを使ってみましょう。

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

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

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals

ポリシーは実行されるでしょうか?いいえ。条件で "/**" によって指定されているように、後続のパス要素が少なくとも 1 つ必要であるためです。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals/

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

はい。このパスには別のパス要素("/animals/" の後ろの部分)がありますが、空白にすぎません。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

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

はい。このパスには、"/animals" の後ろに少なくとも 1 つの要素が存在しているためです。

API 呼び出し:

GET http://artomatic-test.apigee.net/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://artomatic-test.apigee.net/matchtest/animals/cats/wild/

および

GET http://artomatic-test.apigee.net/matchtest/animals/dogs/wild/austrailian

および

GET http://artomatic-test.apigee.net/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://{your_org}-{environment}.apigee.net/mygreatweatherforecast

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

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

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

API プロキシで特定のバックエンド リソースにマップする方法

バックエンド サービスのベース URL にマップされている API プロキシ URL を使用すると(プロキシを作成する場合)、前に述べた /reports リソースや /forecasts リソースなどの特定のリソースに条件フローを追加できます。

呼び出しが /reports リソースや /forecasts リソースに到着すると、Edge でなんらかの処理が行われる必要があるとします。Edge がそれらのリソースに対する呼び出しをリッスンしている必要があるため、この時点では、何を実行すべきかを Edge には指示していません。条件で実行する内容を指示します。Edge の 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>
    

これらの条件では、そのフローに添付するポリシーを使用して、「GET リクエストが URL の /reports/forecasts に到着したら、API デベロッパーが Edge に指示する内容を Edge がすべて実行する」ということを指示します。

次に、条件が満たされたときに実行すべき内容を Edge に指示している例を示します。次の API プロキシの XML では、GET リクエストが https://yourorg-test.apigee.net/mygreatweatherforecast/reports に送信されたら、Edge ではレスポンスの「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 つのデフォルトのフローもあります。条件フローの前に実行される <PreFlow> と条件フローの後に実行される <PostFlow> です。これらは、API プロキシに対してなんらかの呼び出しが行われたときにポリシーを実行する場合に役立ちます。たとえば、アクセス対象のバックエンド リソースに関係なく、すべての呼び出しでアプリの API キーを確認する場合、<PreFlow> に Verify API Key ポリシーを配置できます。フローの詳細については、フローの構成をご覧ください。

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

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

以下を実行できます。

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

たとえば、バックエンドの /developers と /apps リソースに異なるタイプのロジックを適用する必要があるとします。

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

API プロキシ エディタの [Navigator] ペインの [Develop] ビューで、[Proxy Endpoint] の [default] の横の + アイコンをクリックします。

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

  • Flow name: Developers
  • Condition Type: Path
  • Path: /developers

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

次に、/app 用の条件フローを追加し、リクエストの URI と POST 動詞の両方で条件をトリガーしたい場合を想定してみましょう。この構成には、次の設定が関係します。

  • Flow Name: Apps
  • Condition Type: Path and Verb
  • Path: /apps
  • Verb: POST

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

[Navigator] ペインに、[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 プロキシの条件 Flow によって実装されます(フローの構成をご覧ください)。

API プロキシをテスト環境にデプロイすると、次のリクエスト

    http://{org_name}-test.apigee.net/{proxy_path}/apps
    

により、条件が true と評価され、このフローと関連付けられているすべてのポリシーが実行されます。

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

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

このタイプの条件の詳細については、Apigee コミュニティ条件に関係なく照合する方法をご覧ください。

階層 URI のモデル化

場合によっては、階層的な API リソースを使用することがあります。たとえば、Developer Services 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
    

これらのワイルドカードでは、階層 URI は API リソースとして適宜解決されます。

特に 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

実用的な例: パスの末尾の「/」を無視する

Edge デベロッパーは、一般的に、"/cat" と "/cat/" の両方のパス接尾辞を処理する必要があります。これは、一部のユーザーやクライアントが、パスの末尾にスラッシュを追加して API を呼び出す場合があり、条件文でこの追加のスラッシュを処理することができる必要があるためです。この厳密なユースケースについては、Apigee コミュニティをご覧ください

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

        <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://artomatic-test.apigee.net/matchtest/cat
or

GET http://artomatic-test.apigee.net/matchtest/cat/

ポリシーは実行されるでしょうか?はい。正規表現では、「?」文字は、先行する文字の 0 字か 1 字と一致することを意味します。したがって、"/cat" と "/cat/" は両方とも一致します。

API 呼び出し:

GET http://artomatic-test.apigee.net/matchtest/cat/spotted

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

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

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

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

具体的な例を見てみましょう。認証サーバーから、"editor, author, guest" のように、カンマ区切りの文字列として役割のリストが返されたとします。

editor 役割が存在するかどうかをテストする場合、次の構成では、"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)"