API Management のポリシーで API の利用可能時間を制御してみる

Pocket

API Management のポリシーで API の利用可能時間を制御してみる

はじめに

Azure API Management は、API を統合的に管理することができる Azure のサービスです。
その API Management の機能の一つに ポリシー というものがあります。
ポリシーを使用することで、「呼び出し元 IP の制限」や「JSON ⇔ XML の変換」など様々な処理を実現することができます。
この記事では、ポリシーの活用例を一つご紹介したいと思います。

ポリシー 概要

ポリシーの編集方法とスコープについては、下記のページをご確認ください。

ポリシー定義には、下記のようなルールがあります。

  • 基本的に XML で定義します。
    • 例外として、後述する ポリシー式 (C#) があります。
  • 下記 4 つのブロックがあり、ポリシーが適用されるタイミングが異なります。

  • inbound ブロック
    • API がリクエストされたときに、最初に適用するポリシーを定義するブロック。
      • 例) HTTP ヘッダーを確認し、特定のヘッダーが含まれていなかったり、ヘッダーの値が指定の値と異なる場合はエラーとする。 など…
  • backend ブロック
    • API Management からバックエンドへリクエストするときに適用するポリシーを定義するブロック。
      • 例) バックエンドから HTTP ステータスコード:500 が戻ってきたとき、10 秒待ってからリトライする。 など…
  • outbound ブロック
    • API Management からクライアントへレスポンスするときに適用するポリシーを定義するブロック。
      • 例) バックエンドからの XML のレスポンスを、JSON に変換して、クライアントにレスポンスする。 など…
  • on-error ブロック
    • リクエストの処理中にエラーが発生したときに適用するポリシーを定義するブロック。
      • 例) エラーが発生したリクエストの情報を、エラー通知用の URL に送信する。 など…

途中でエラーが発生しない限り、inbound ⇒ backend ⇒ outbound の順番でポリシーが適用されます。
下記のページに、用意されているポリシーの一覧があります。

様々なポリシーが用意されていますが、「それだけでは、やりたいことが実現できない…」といったこともあると思います。
そのようなときは、ポリシー式 (C#) を使用することも可能です。

用意されているポリシーと、ポリシー式 (C#) を組み合わせることで、幅広い対応が可能となります。

利用可能時間を制御するポリシーを書いてみる

さっそく、この記事の目的である API の利用可能時間を制御するポリシー を記述していきます。

どのブロックに記述するか?

上述のとおり、ポリシー定義には「inbound」、「backend」、「outbound」、「on-error」の 4 つのブロックが存在します。
「利用可能時間の制御ポリシー」は、どのブロックに記述すればよいでしょうか?

まず、ポリシーがどのように動作すればいいか、考えてみます。

  • 利用可能時間内にクライアントからのリクエストが来たとき
    • クライアントからのリクエストをバックエンドへ送り、バックエンドからのレスポンスをクライアントに戻す。
  • 利用可能時間外にクライアントからのリクエストが来たとき
    • クライアントにエラーのレスポンスを戻し、バックエンドへのリクエストを送らない。

このように動作すれば良いでしょう。
バックグラウンドへの送信前に制御したいので、今回は「inbound」にポリシーを記述します。

どのポリシーを使用するか?

今回は、下記のポリシーとポリシー式を使用します。

  • set-variable
    • 変数を定義し、値を設定することができるポリシーです。
  • choose
    • プログラミング言語の if のように、ポリシーの適用を分岐させることができるポリシーです。
  • return-response
    • 任意のレスポンス内容を定義することができます。
      利用時間外のリクエストに対するエラーレスポンスを定義するために使用します。

ポリシー定義

利用可能時間を「日本時間 9:00 ~ 18:30」と想定し、定義したポリシーが下記になります。

<policies>
    <inbound>
        <base />
        <!-- 変数:利用可能開始時間を HH:mm:ss で設定 -->
        <set-variable value="09:00:00" name="serviceStartTime" />
        <!-- 変数:利用可能終了時間を HH:mm:ss で設定 -->
        <!-- ※この時間は、利用可能時間には含まれません。 -->
        <set-variable value="18:30:00" name="serviceEndTime" />
        <!-- 変数:現在日時がサービス提供時間内か否かの判定結果 -->
        <set-variable value="@{
            // アクセス日時
            DateTime accessTimeJst = DateTime.UtcNow.AddHours(9);
            string accessDateStr = accessTimeJst.ToString("yyyy-MM-dd");

            // サービス提供開始日時
            string serviceStartTimeStr = accessDateStr + " " + (string)context.Variables["serviceStartTime"];
            DateTime serviceStartTime = DateTime.Parse(serviceStartTimeStr);

            // サービス提供終了日時
            string serviceEndTimeStr = accessDateStr + " " + (string)context.Variables["serviceEndTime"];
            DateTime serviceEndTime = DateTime.Parse(serviceEndTimeStr);

            // 日時の比較
            if (serviceStartTime.TimeOfDay <= accessTimeJst.TimeOfDay && accessTimeJst.TimeOfDay < serviceEndTime.TimeOfDay) {
                // 提供時間内
                return true;
            } else {
                // 提供時間外
                return false;
            }
        }" name="isAvailable" />
        <choose>
            <when condition="@(!(Boolean)context.Variables["isAvailable"])">
                <!-- サービス提供時間外 -->
                <return-response response-variable-name="OutOfService-Response">
                    <set-status code="503" reason="Service Unavailable" />
                    <set-header name="content-type" exists-action="override">
                        <value>application/json</value>
                    </set-header>
                    <set-body>@{
                        return Newtonsoft.Json.JsonConvert.SerializeObject(new {
                            accessTimeJst = DateTime.UtcNow.AddHours(9).ToString("yyyy/MM/dd HH:mm:ss"),
                            message       = "Out of Service Hours"
                        });
                    }</set-body>
                </return-response>
            </when>
        </choose>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
  • set-variable ポリシー を使用して serviceStartTimeserviceEndTime という変数を定義し、利用可能開始/終了時間を設定します。
  • set-variable ポリシー を使用して isAvailable という変数を用意し、その値は ポリシー式 (C#) で求めた結果を設定するようにします。
    • アクセスされた日時と利用可能開始/終了時間を比較し、利用可能時間内なら「true」、利用可能時間外なら「false」を設定しています。
  • choose ポリシー を使用して、 isAvailable の値で判定を行い、
    利用可能時間外のときは return-response ポリシー を使用して、エラーのレスポンスをクライアントに戻します。

動作確認

上記のポリシーを定義した API を Postman というツールを使用して、呼び出してみます。
今回 呼び出す API は、わかりやすいようにアクセスした時間をレスポンス内容に含めています。

利用可能時間内 (18:10)
バックエンドまでリクエストされ、バックエンドからのレスポンスが戻ってきています。

利用可能時間内の API リクエスト結果

利用可能時間外 (18:30)
バックエンドからのレスポンスではなく、ポリシーで定義したエラーのレスポンスが戻ってきています。

利用可能時間外の API リクエスト結果

まとめ

無事、API Management ポリシーだけで、利用可能時間の制御を実現することができました。
この記事のポリシーのままでは、日付跨ぎのケースや、曜日によって利用可能時間が異なるケースなどには対応できませんが、少し変更を加えれば対応できると思います。

また、こちらのページに、いくつか他のサンプルが掲載されています。

API 自体に変更は加えずに、API Management で制御を追加することができるのは、開発面・運用面の両方で大きな効果があると思います。
API Management ポリシーを、ぜひ活用していただければと思います。

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です