このページは Apigee と Apigee ハイブリッドに適用されます。
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>
サポートされている条件演算子には、=
(等しい)、!=
(等しくない)、>
(より大きい)があります。読みやすくするために、条件をテキストとして記述することもできます(equals
、notequals
、greaterthan
)。
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
演算子: 単純なパターン マッチング- JavaRegex 演算子: マッチングのよりきめ細かな制御
MatchesPath
演算子: パス フラグメント マッチング
一致
まず、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
ポリシーは実行されるでしょうか?いいえ。ワイルドカードは(大文字と小文字に関係なく)すべての文字と一致しますが、小文字の a
は A
とは一致しません。
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]
またはグループ化形式の正規表現を使用します。これは、文字 a
、b
、c
と一致します。
<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>
API 呼び出し:
GET http://example.com/matchtest/cat
ポリシーは実行されるでしょうか?はい。ここでは正規表現を使用しており、[cbr]
式は c
、b
、または 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 プロキシです。条件付きフローについては、以下で詳しく説明します。
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 つの条件付きフローを追加します。
新しいプロキシ エディタ
条件フローを追加するには:
- プロキシ エディタの [Develop] タブを選択します。
- 左側のペインで、[Proxy endpoints] > [default] を選択します。
[default] を選択します。" class="l10n-absolute-url-src screenshot" l10n-attrs-original-order="class,width,alt,src" src="https://cloud.google.com/static/apigee/docs/api-platform/fundamentals/images/proxy-endpoints-default.png" width="35%" />
- [Response] ペインの上にある [+] ボタンをクリックします。
- [Add Conditional Flow] ダイアログで次の構成を入力します。
- フロー名:
Developers
- 条件タイプ:
Path
- パス:
/developers
URI の末尾が
/developers
の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。 - フロー名:
- 次に、
/apps
用の条件付きフローを追加し、リクエストの URI とPOST
動詞の両方で条件をトリガーしたいと想定します。この構成には、以下の設定が含まれます。- フロー名:
Apps
- 条件タイプ:
Path and Verb
- パス:
/apps
- 動詞:
POST
URI の末尾が
/apps
で、動詞がPOST
の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。 - フロー名:
追加されたフローは [Response] ペインに表示されます。
従来バージョンのプロキシ エディタ
API プロキシ エディタの [Navigator] ペインの [Develop] ペインで、[Proxy Endpoints] の [default] の隣の をクリックします。
[New Conditional Flow] ウィンドウで、次のキー構成を入力します。
- フロー名:
Developers
- 条件タイプ:
Path
- パス:
/developers
URI の末尾が /developers
の呼び出しがプロキシに送信された場合、この条件がトリガーされます(そして、ポリシーが実行されます)。
次に、/apps
用の条件付きフローを追加し、リクエストの URI と POST
動詞の両方で条件をトリガーしたいと想定します。この構成には、次の設定が含まれます。
- フロー名:
Apps
- 条件タイプ:
Path and Verb
- パス:
/apps
- 動詞:
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 プロキシの条件付きフローによって実装されます(フローの構成をご覧ください)。
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)"