条件文は、あらゆるプログラミング言語でよく使用される制御構造です。プログラミング言語と同様、API プロキシ構成では Flow、Policy、Step、RouteRule での条件文をサポートしています。条件文を定義することで、API の動的な動作を定義できます。動的な動作を使用することで、たとえばモバイル デバイスの場合にのみ XML を JSON に変換したり、バックエンド URL をコンテンツ タイプやリクエスト メッセージの HTTP 動詞に基づいてルーティングしたりできます。
このトピックでは、コードを作成することなく、条件を使用して API 管理機能をランタイムに動的に適用する方法を示します。
条件文の構成
条件動作を API プロキシに実装するには条件と変数を組み合わせて使用します。 条件文の作成には Condition 要素を使用します。次に、空の条件を示します。
<Condition></Condition>
条件文を作成するには、条件演算子と変数を追加して、次のような構造を作成します。
<Condition>{variable.name}{operator}{"value"}</Condition>
サポートされている条件演算子には、=
(等しい)、!=
(等しくない)、>
(より大きい)があります。読みやすくするために、条件をテキストとして記述することもできます(equals
、notequals
、greaterthan
)。
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 に接続すると、「条件付きフロー」を作成したことになります。条件付きフローは、条件が true と評価された場合にのみ実行されます。条件付きフローには Policy をいくつでも接続できます。条件付きフローを使用すると、特定の条件に合致するリクエストやレスポンスのメッセージ用のきわめて特化された処理ルールを作成できます。
たとえば、リクエスト動詞が 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>
このような条件付きフローを定義したら、そこに Policy を接続して、API プロキシで GET リクエストにはあるポリシーの一式、POST リクエストには別のポリシーの一式を強制するようにできます。
全体的なリファレンス情報については、次のリソースをご覧ください。
例 1
以下の例に示されているのは Convert-for-devices
という名前の単一の条件付きフローで、ProxyEndpoint のレスポンス フローに構成されています。条件が適用されるエンティティに対し、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 演算子: 単純なパターン マッチング
- JavaRegex 演算子: 一致の詳細な制御
- MatchesPath 演算子: パス フラグメントの一致
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
ポリシーは実行されるでしょうか?はい。「?
」数量子は、先行する文字の 1 つに一致するか、いずれにも一致しません。この場合は、「a」という文字は存在しないため、条件は true と評価されます。
API 呼び出し:
GET http://artomatic-test.apigee.net/matchtest/caat
ポリシーは実行されるでしょうか?いいえ。「?」数量子は先行する文字の 1 つ(「a
」)に一致します。
次に、正規表現の「[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 プロキシで特定のバックエンド リソースにマップする方法
(プロキシの作成時に)API プロキシ URL をバックエンド サービスのベース 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 プロキシには、条件付きフローの前に実行される <PreFlow>
と、条件付きフローの後に実行される <PostFlow>
という 2 つのデフォルト フローがあります。これらは、API プロキシに対して任意の呼び出しが行われたときにポリシーを実行するのに役立ちます。たとえば、アクセスされるバックエンド リソースに関係なく、すべての呼び出しでアプリの API キーを検証する場合は、Verify API Key ポリシーを <PreFlow>
に配置します。フローの詳細については、フローの構成をご覧ください。
バックエンド リソースに対する条件付きフローの作成
API プロキシでバックエンド リソースへの条件付きフローを定義することは完全に任意選択です。ただし、条件付きフローを使用すると、細かい管理とモニタリングを適用できます。
以下を実行できます。
- API モデルのセマンティクスを反映する方法での管理を適用する
- 個々のリソースパス(URI)にポリシーとスクリプト動作を適用する
- Analytics Services のための細かな指標を収集する
たとえば、バックエンドの /developers と /apps リソースに異なるタイプのロジックを適用する必要があるとします。
このためには、API プロキシで、/developers
および /apps
の 2 つの条件付きフローを追加します。
API プロキシ エディタの [Navigate] ペインの [Develop] ビューで、[Proxy Endpoints] の [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 パスを評価する単なる条件付きフローです(proxy.pathsuffix 変数では、ProxyEndpoint 構成で構成されている BasePath に続くリクエストの URI を識別します)。
定義した各 API リソースは、API プロキシの条件付きフローによって実装されます(フローの構成をご覧ください)。
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"'
request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"
\u0022
に置き換えることです。たとえば、次の式は有効であり、期待される結果となります。request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"