5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Microsoft Graph を使ってみよう : 変更通知 (Webhook)

Last updated at Posted at 2018-05-22

Microsoft Graph の変更通知

Webhook を使った一般的な仕組みで、One Drive にファイルを保存した時や、新しいユーザーがグループに追加されたなどのイベントを、任意の API に通知できます。

現在は以下のリソースで通知がサポートされています。

  • Messages (メール)
  • イベント (予定)
  • 連絡先
  • ユーザー
  • グループ
  • グループ会話
  • SharePoint サイトに関連付けられたドライブを含む、OneDrive で共有されるコンテンツ
  • ユーザーの個人用 OneDrive フォルダー

以下 3 つの処理で変更通知を利用します。

1. Webhook でイベントが発生した際にくる通知を処理
2. サブスクリプションの登録
3. 有効期限が切れる前にサブスクリプションの更新

Webhook の作成

まずは通知を受け取るための Webhook を用意します。今回は Functions App を使っていきます。ここでは 60 分だけ Functions App を試せるサイトを使います。

1. https://azure.microsoft.com/ja-jp/try/app-service/ にアクセスし、Functions App を選択。「Functions を試す」をクリック。

Capture.PNG

2. 「Webhook ⁺ API」、「C#」を選択して「Create this function」をクリック。

Capture.PNG

3. 任意のプロバイダーでサインイン。ここでは GitHub を利用。

Capture.PNG

4. Functions が準備されたら以下のコードで中身を差し替え。Subscription が作成された時点で validationToken が渡されるためそれを返信。また Content の中身をログに出力。詳細は サブスクリプションを作成する を参照。

C#
using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    log.Info(await req.Content.ReadAsStringAsync()); 
    // parse query parameter
    string token = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "validationToken", true) == 0)
        .Value;

    if(token != null){
        log.Info(token);
    }
    return token != null
        ? req.CreateResponse(HttpStatusCode.OK, token)
        : req.CreateResponse(HttpStatusCode.OK);
}

4. Function が作成されるので「Get function URL」をクリックして Webhook アドレスを取得。

Capture.PNG

サブスクリプションの登録

今回は Graph エクスプローラーを使って登録します。

  • Webhook は上記で作成したものを利用
  • 予定が作成または削除された場合に通知

Graph エクスプローラー にアクセスしてサインイン。以下リクエストを実行。

※ expirationDateTime は現在から 3 日以内に設定

POST: https://graph.microsoft.com/v1.0/me/subscriptions

Body
{
  "changeType": "created,deleted",
  "notificationUrl": "https://Functions065bac0f.azurewebsites.net/api/HttpTriggerCSharp1?code=7e97ec30126a1b0c3002c9ff06edaa5a12ef6835",
  "resource": "me/events",
  "expirationDateTime": "2018-05-16T23:23:59Z",
  "clientState": "mywebhooktest"
}

結果としてサブスクリプション ID が返ります。

応答
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#subscriptions/$entity",
    "id": "a5d287ef-0d54-4116-86e8-a45bc1b551a8",
    "resource": "me/events",
    "changeType": "created,deleted",
    "clientState": "mywebhooktest",
    "notificationUrl": "https://Functions065bac0f.azurewebsites.net/api/HttpTriggerCSharp1?code=7e97ec30126a1b0c3002c9ff06edaa5a12ef6835",
    "expirationDateTime": "2018-05-16T23:23:59Z"
}

SDK を使った場合

C#
await graphClient.Subscriptions.Request().AddAsync(new Subscription()
{
    ChangeType = "created, deleted",
    NotificationUrl = "https://Functions065bac0f.azurewebsites.net/api/HttpTriggerCSharp1?code=7e97ec30126a1b0c3002c9ff06edaa5a12ef6835",
    Resource = "me/events",
    ExpirationDateTime = new DateTimeOffset(2018, 5, 16, 23, 23, 59, new TimeSpan(9)),
    ClientState = "mywebhooktest"
});

動作のテスト

ここで一旦動作をテストしてみます。

1. 予定を Outlook で作成。

Capture.PNG

2. Functions App のログから Webhook に通知された内容を確認。

  • changeType が created のため作成
  • resource に実際のアイテムのアドレス
  • 詳細は resourceData にあるが、詳細は含まれない。
受信したBody
{
    "value": [
        {
            "subscriptionId": "a5d287ef-0d54-4116-86e8-a45bc1b551a8",
            "subscriptionExpirationDateTime": "2018-05-16T23:23:59+00:00",
            "changeType": "created",
            "resource": "Users/6746d79d-8c77-4eec-a61f-cce6beb162f7/Events/AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA=",
            "resourceData": {
                "@odata.type": "#Microsoft.Graph.Event",
                "@odata.id": "Users/6746d79d-8c77-4eec-a61f-cce6beb162f7/Events/AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA=",
                "@odata.etag": "W/\"DwAAABYAAABvNJgFk4PxRY7qUEy18VJ6AAAD3WON\"",
                "id": "AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA="
            },
            "clientState": "mywebhooktest"
        }
    ]
}

3. Graph エクスプローラーでリソースにアクセスし、予定が取れることを確認。

Sketch.png

4. 同様に削除もテスト。changeType が deleted で削除イベントであることが分かる。また削除されたリソースの情報も特定可能。

受信したBody
{
    "value": [
        {
            "subscriptionId": "a5d287ef-0d54-4116-86e8-a45bc1b551a8",
            "subscriptionExpirationDateTime": "2018-05-16T23:23:59+00:00",
            "changeType": "deleted",
            "resource": "Users/6746d79d-8c77-4eec-a61f-cce6beb162f7/Events/AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA=",
            "resourceData": {
                "@odata.type": "#Microsoft.Graph.Event",
                "@odata.id": "Users/6746d79d-8c77-4eec-a61f-cce6beb162f7/Events/AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA=",
                "@odata.etag": "W/\"CQAAAA==\"",
                "id": "AAMkAGExMTQzMTU1LTE3ZGYtNDU1Ny1iMzczLWQ1MmU0YjQxNmEzNgBGAAAAAACFQuNJIe4VSIJxcTi2cbakBwBvNJgFk4PxRY7qUEy18VJ6AAAAAAENAABvNJgFk4PxRY7qUEy18VJ6AAAD3lKsAAA="
            },
            "clientState": "mywebhooktest"
        }
    ]
}

サブスクリプションの更新

Graph エクスプローラーを使って更新してみます。

サブスクリプションの ID を指定した URL に対して、Patch として送信。ここでも有効な expirationDateTime は 3 日以内です。

PATCH: https://graph.microsoft.com/v1.0/me/subscriptions/{id}

Body
{
   "expirationDateTime":"2018-05-17T00:00:00Z"
}

結果として更新された expirationDateTime が返ります。
Capture.PNG

SDK を使った場合

C#
await graphClient.Subscriptions["a5d287ef-0d54-4116-86e8-a45bc1b551a8"].Request().UpdateAsync(new Subscription()
{
    ExpirationDateTime = new DateTimeOffset(2018, 5, 17, 0, 0, 0, new TimeSpan(9))
});

サブスクリプションの削除

サブスクリプションの ID を指定した URL に対して、Delete を送信すれば削除完了。

DELETE: https://graph.microsoft.com/v1.0/me/subscriptions/{id}

Capture.PNG

SDK を使った場合

C#
await graphClient.Subscriptions["a5d287ef-0d54-4116-86e8-a45bc1b551a8"].Request().DeleteAsync();

サブスクリプションのリスト

現在のサブスクリプション一覧はベータ機能として提供されています。

GET: https://graph.microsoft.com/beta/subscriptions

Capture.PNG

SDK を使った場合

C#
var subscriptions = await graphClient.Subscriptions.Request().GetAsync();

Tips

Webhook を使う場合の Tips をいくつか紹介します。

clientState
Webhook が Microsoft Graph から実行されたかを検証するためには、指定した clientState の値を検証します。

サブスクリプションの更新
かならず有効期限内に実施する。期限が切れた場合更新ができないため、新規作成となる。

詳細の取得
変更通知には、変更されたアイテムの詳細は入っていないため、別途必要に応じて詳細を所得するが、通知に対しては極力早く 200 OK を返したほうがいいため、一旦キューに通知情報を格納し、キューをトリガーとして別のプログラムで詳細の取得や処理を行う。

デルタクエリ
変更通知が来た場合、個別のアイテムを取得するためにリソースをダイレクトに呼び出してもいいが、シナリオによってはデルタクエリを利用して、差分を一括取得することも可能。

まとめ

ポーリングで差分を取るのは効率が悪く、リアルタイムの更新も出来ませんが、Webhook ならより効率のいいプログラムが書けます。通知には実際のデータは含まれませんので、差分クエリも同時に活用してください。

目次へ戻る

参照

Microsoft Graph の Webhooks での作業
Microsoft Graph の Webhooks での作業(英語) ※最新情報はこちらを確認してください※
リソースの種類別のサブスクリプションの最大の長さ
サブスクリプション

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?