Microsoft Graph と Azure Bot Service で Office 365 対応の会議室＆スケジュール予約 Bot を開発する: (1) Graph API による操作

[Microsoft 365](https://www.office.com/) (旧称 Office 365、以下 M365) はクラウド利用を前提とした Office 製品群で、ローカル環境に Office ソフトウエアをインストールしてもよし、インストール不要でブラウザーから利用してもよし、Outlook | Excel | Word | PowerPoint | OneNote などのファイルのバックアップや、会社や学校での情報共有が自在なサービスになっています。また、M365 の情報は認証を経て Web API でアクセスすることが可能であり(*1)、属する組織 (会社や学校) のドメインで共有されている情報を用いて、空き時間情報を取得したり、スケジュール予約をしたりすることができます。

> (*1) M365 を含むマイクロソフトのクラウド製品にアクセスできる Web API 群は、まとめて [Microsoft Graph](https://developer.microsoft.com/ja-jp/graph) と呼ばれています

今回は、この M365 の Graph API を用いて、会議室や関係者のスケジュールの空きを見つけて予約を行うチャットボットを構成する方法を紹介します。

- 会議室＆スケジュール予約Bot開発シリーズ
    - (1) Microsoft 365 Graph API による操作 (←イマココ)
    - (2) (仮)Azure Bot Service からの OAuth 認証
    - (3) (仮)チャットボットのフロー構成を考える

- 準備
    - M365 アカウント
    - Rest API テストツール

- 手順


# 準備

## M365 アカウント

この Graph API の操作を確認する段階では、会社や学校でご利用中の M365 アカウントでも大丈夫です。
管理者による制限で API の利用 (アクセスや操作) ができない場合は、開発者用サブスクリプション(無料、90日間有効) を作成し、ご自分で権限をコントロールできる M365 ドメイン(*.onmicrosoft.com)を取得してください。

[Microsoft 365 デベロッパーセンター > 開発者プログラム](https://developer.microsoft.com/ja-jp/microsoft-365/dev-program)

## Rest API テストツール

[Postman](https://www.postman.com/)、[Talend API Tester](https://www.talend.com/products/application-integration/cloud-api-tester/) (←どちらも無償で利用できます) などなど、お好みのものをお使いください。こちらの手順では Talend API Tester の Chrome Extention を使用しています。

# 手順

## 1. Microsoft Graph デベロッパーセンターでの操作

Microsoft Graph から M365 の情報にアクセス、操作を行う上で、[Microsoft Graph Explorer]((https://developer.microsoft.com/ja-jp/graph/graph-explorer)) という、ブラウザーから動作を確認できるツールが用意されています。こちらで M365 へのアクセスや操作内容を確認します。


### 1.1 M365 サインインと Microsoft Graph からの M365 アクセスの確認

ブラウザーから [Microsoft Graph Explorer](https://developer.microsoft.com/ja-jp/graph/graph-explorer) を開きます。

![20200702_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/1747213f-ee89-6135-ffea-b06cd0d299fb.jpeg)

左メニューバーの *認証* の欄にある **[サインイン]** をクリックして、M365 アカウントでサインインします。

![20200702_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/efb383dd-909c-dff5-c0ea-2fe8ef738c52.jpeg)

ユーザー名および M365 アカウントが表示されたのを確認してから、Graph Explorer に用意されているサンプルクエリで動作を確認していきます。

![20200702_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/f7b026d0-afa7-6e6e-1fff-2b3db0c52b96.jpeg)

>サインインできない場合は、ブラウザーのポップアップがブロックされていないことを確認してください。

![20200702_04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/4c92a9f2-51be-6b25-cc4f-0d6b1476d37c.jpeg)

左のメニューバーの *サンプル クエリ* の中から *>はじめに* に含まれている **自分のプロファイル** をクリックします。

![20200702_05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/b29b0fab-467b-cb8c-5d54-30c77e308ede.jpeg)

画面中央上部に Rest API の URI & アクセスに必要な情報 が表示されます。
画面中央下側の *応答のプレビュー* に、サインインで使用しているユーザー情報が表示されれば、無事 Microsoft Graph の Rest API で M365 プロファイルにアクセスができています。

> Rest API でアクセスする場合は以下を設定します。
> - URI
> [GET] https://graph.microsoft.com/v1.0/me
> - Header
> Authorization: Bearer *user_token*
> Content-Type: application/json
>
> 詳細は [Microsoft Docs > Microsoft Graph > ユーザーの取得](https://docs.microsoft.com/ja-JP/graph/api/user-get) を確認してください。
> Authorization に設定する認証トークン(*user_token*)は [後述](https://qiita.com/drafts/40eef880b6e560d401c0#21-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97) します。


### 1.2 アクセス許可の設定

今回はスケジュールの作成を行う権限が必要になりますので、Microsoft Graph からのアクセス許可を設定します。ユーザー名の右側に表示される **⚙** をクリックし、表示される **[アクセス許可を選択する]** をクリックします。

![20200702_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/68737d54-add2-1500-3510-65ef16cee427.jpeg)

アクセス許可の一覧から **Calendars** を探してクリックします。

![20200702_07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/bcec7865-9b63-1624-8f44-02123ee38601.jpeg)

**Calendars.ReadWrite** をクリックして✓(チェック)をつけ、画面下部の [同意] をクリックして設定します。

![20200702_08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/c773d6ac-8f5a-4e36-02d0-5f9941e0d360.jpeg)

*要求されているアクセス許可* のポップアップ画面が表示されますので、**[承諾]** をクリックして設定を完了します。

![20200702_09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/91d44d19-c1f1-2d81-4522-e5a99d302500.jpeg)

### 1.3 Microsoft Graph から Outlook 予定表へのアクセス＆操作

#### 1.3.1　空き時間から会議スケジュールを検索する

Microsoft Graph を使って、会議の参加メンバーや会議室の Outlook スケジュールを参照して、会議を設定できる日程を検索することができます。

[Microsoft Docs > Microsoft Graph > 会議の日時を検索する](https://docs.microsoft.com/ja-JP/graph/api/user-findmeetingtimes)

Graph Explorer のサンプルクエリから **Outlook カレンダー > 会議の日時を検索する** をクリックします。

![20200702_10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/2e009e0a-5d0f-a20b-1df9-d3adf970aab3.jpeg)

今回は POST で、Request Body に検索するメンバーや日時を記載します。
以下のように、とりあえずユーザーは1人(参加必須)、7/1 の 9:00-17:00 (ここではUTCで設定)の間で1時間の会議を検索するには以下のようになります;

```
{
    "attendees": [
        {
            "emailAddress": {
                "address": "user01@YOUR_ACCOUNT.onmicrosoft.com"
            },
            "type": "Required"
        }
    ],
    "timeConstraint": {
        "timeslots": [
            {
		"start": {
                    "dateTime": "2020-07-01T00:00:00.0000000",
                    "timeZone": "UTC"
                },
                "end": {
                    "dateTime": "2020-07-01T08:00:00.0000000",
                    "timeZone": "UTC"
                }            }
        ]
    },
    "meetingDuration": "PT1H"
}
```

こちらを **要求本文** にコピー＆ペーストし、Email はサインインしているアカウントに変更、時間も適切なものに変更してください。**[クエリーの実行]** をクリックして送信します。

![20200702_11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/3760072a-f991-341b-b726-2b1342567128.jpeg)

応答に **OK - 200** と表示され、*応答のプレビュー* に条件に合った会議時間が提示されます。

![20200702_12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/d1ee2f1e-d0de-e131-4806-891488964034.jpeg)


例えば、以下のように 7/1 の 9:00-10:00 が第1候補として、複数の候補日程が提示されます。

```
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.meetingTimeSuggestionsResult",
    "emptySuggestionsReason": "",
    "meetingTimeSuggestions": [
        {
            "confidence": 100,
            "order": 1,
            "organizerAvailability": "free",
            "attendeeAvailability": [],
            "locations": [],
            "meetingTimeSlot": {
                "start": {
                    "dateTime": "2020-07-01T00:00:00.0000000",
                    "timeZone": "UTC"
                },
                "end": {
                    "dateTime": "2020-07-01T01:00:00.0000000",
                    "timeZone": "UTC"
                }
            }
        },
 :
```

#### 1.3.2　会議の予定を作成する

今度は、Microsoft Graph で Outlook の会議(イベント)を作成してみます。

[Microsoft Docs > Microsoft Graph > イベントを作成する](https://docs.microsoft.com/ja-JP/graph/api/user-post-events)

Graph Explorer のサンプルクエリから **Outlook カレンダー > 会議の予約** をクリックします。

![20200702_13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/dec67444-2e4c-82c9-e425-089971db5092.jpeg)

POST でアクセスし、Request Body に会議参加メンバーや会議室、日時を記載します。
以下のように、例えばユーザーは送信者本人ひとり(参加必須)、7/1 の 13:00-14:00 (ここではUTCで設定) に会議を作成するには以下のようになります;

```
{
	"subject": "My event",
	"start": {
		"dateTime": "2020-07-01T04:00:00.0000000",
		"timeZone": "UTC"
	},
	"end": {
		"dateTime": "2020-07-01T05:00:00.0000000",
		"timeZone": "UTC"
	}
}
```

こちらを **要求本文** にコピー＆ペーストし、Email はサインインしているアカウントに変更、時間も適切なものに変更してください。**[クエリーの実行]** をクリックして送信します。

応答に **Created - 201** と表示されたら会議の作成は完了です。

![20200702_14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/c8054b82-cdbc-7272-a3b1-8172762faa33.jpeg)

操作に使用しているユーザーの Outlook にアクセスし、会議が作成されているのを確認してください。

![20200702_15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/8abf57ba-8391-9f6d-274f-38ab4f09e3a8.jpeg)


## 2. Rest API による操作

今度は Rest API のテストツールから M365 へのアクセスや操作を行います。

Microsoft Graph で M365 にアクセスする場合には認証トークンが必要です。通常では チャットボットを含む Web や PC, モバイルアプリなどから Graph API を用いてアクセスを行うことになり、アプリ自体を予め Microsoft ID プラットフォームに登録しておく必要があります。

[Microsoft Docs > Microsoft Graph > Microsoft Graph の認証と承認の基本方法](Microsoft Graph の認証と承認の基本方法)

アプリ登録はチャットボット作成の際に行いますので、Microsoft Graph の動作確認を行う今回は Microsoft Graph Explorer から発行される認証トークンを利用します。

### 2.1 認証トークンの取得

[Microsoft Graph Explorer](https://developer.microsoft.com/ja-jp/graph/graph-explorer) にサインインした状態で、画面中央上部にある、**アクセストークン** をクリックします。トークンが表示されたら、選択してコピー、または **📄** をクリックしてコピーし、ローカルに保存しておきます。

![20200702_16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/10fe4699-d88a-c87f-0ef5-b4c404984887.jpeg)

### 2.2 Rest API のテストツールから Outlook 予定表へのアクセス＆操作

Microsoft Graph Explorer から行ったのと同じ操作を (＋ちょっと実践的に Request Body を複雑にして) 行ってみます。

#### 2.2.1　空き時間から会議スケジュールを検索する

再掲ですが、使用する API はこちら; 
[Microsoft Docs > Microsoft Graph > 会議の日時を検索する](https://docs.microsoft.com/ja-JP/graph/api/user-findmeetingtimes)

YOUR_ACCESS_TOKEN は 2.1 でコピーしておいた認証トークンに置き換えます。

```
POST https://graph.microsoft.com/v1.0/me/findMeetingTimes
Content-Type: application/json
Authorization: bearer YOUR_ACCESS_TOKEN
```

Request Body は例えば以下のようになります。
会議の参加者 user01 と user02、およびリソース(会議室)である room01 の空きを 7/1, 13:00 ～ 7/2, 18:00 (日本時間)の範囲で、2 時間の会議ができる日時を検索します。参加者および日時範囲を適切に修整します。

```
{
   "attendees":[
      {
         "emailAddress":{
            "address":"user01@YOUR_ACCOUNT.onmicrosoft.com"
         },
         "type":"Required"
      },
      {
         "emailAddress":{
            "address":"user02@YOUR_ACCOUNT.onmicrosoft.com"
         },
         "type":"Required"
      },
      {
         "emailAddress":{
            "address":"room01@YOUR_ACCOUNT.onmicrosoft.com"
         },
         "type":"resource"
      }
   ],
   "timeConstraint":{
      "timeslots":[
         {
            "start":{
               "dateTime":"2020-07-01T13:00:00.0000000",
               "timeZone":"Tokyo Standard Time"
            },
            "end":{
               "dateTime":"2020-07-02T18:00:00.0000000",
               "timeZone":"Tokyo Standard Time"
            }
         }
      ]
   },
   "meetingDuration":"PT2H"
}
```

> この room01 は Outlook のリソースとして登録されているため、"type":"resource" として、いち参加者のように "attendees" に追加しています。ユーザーとして登録されている場合は、"locationConstraint" のパラメーターで追加します。(詳細は [ドキュメント](https://docs.microsoft.com/ja-JP/graph/api/user-findmeetingtimes?view=graph-rest-1.0&tabs=http#example) を参照してください)
> また、日本時間で日時を設定するため、"timeZone" を "Tokyo Standard Time" に設定しています。

Request URI, Header, Body をコピー＆ペーストしたら、リクエストを送信します。

![20200702_17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/50108ce1-b44f-6fe6-ad9d-40c023223634.jpeg)

Response 200 が返り、候補日時が Response Body として取得できます。

![20200702_18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/fddf25bb-7d54-66b5-b3a3-96d5048bc6f2.jpeg)

> 指定された日時の範囲と、稼働時間内で候補日時が検索され、提示されます。また、UTC 表記になっています。

```
{
   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.meetingTimeSuggestionsResult",
   "emptySuggestionsReason": "",
   "meetingTimeSuggestions":[
      {
         "confidence": 100.0,
         "organizerAvailability": "free",
         "attendeeAvailability":[
            {
               "availability": "free",
               "attendee":{
                  "emailAddress":{
                     "address": "user02@YOUR_ACCOUNT.onmicrosoft.com"
                  }
               }
            },
            {
               "availability": "free",
               "attendee":{
                  "emailAddress":{
                     "address": room01@YOUR_ACCOUNT.onmicrosoft.com"
                  }
               }
            },
         ],
   "locations":[],
   "meetingTimeSlot":{
      "start":{
         "dateTime": "2020-07-01T05:00:00.0000000",
         "timeZone": "UTC"
      },
      "end":{
         "dateTime": "2020-07-01T07:00:00.0000000",
         "timeZone": "UTC"
      }
   }
},
:
```


#### 2.2.2　会議の予定を作成する

再掲ですが、使用する API はこちら; 
[Microsoft Docs > Microsoft Graph > イベントを作成する](https://docs.microsoft.com/ja-JP/graph/api/user-post-events)

YOUR_ACCESS_TOKEN は 2.1 でコピーしておいた認証トークンに置き換えます。

```
POST https://graph.microsoft.com/v1.0/me/events
Content-Type: application/json
Authorization: bearer YOUR_ACCESS_TOKEN
```

Request Body は例えば以下のようになります。
会議の参加者 user01 と user02、リソース(会議室) room01 に 7/1, 15:00 ～ 16:00 (日本時間)の会議(イベント)を作成します。参加者および日時範囲を適切に修整します。

```
{
	"subject": "Plan Meeting",
	"body": {
		"contentType": "HTML",
		"content": "こちらで今期の企画会議を設定します"
	},
	"start": {
		"dateTime": "2020-07-01T15:00:00",
		"timeZone": "Tokyo Standard Time"
	},
	"end": {
		"dateTime": "2020-07-01T16:00:00",
		"timeZone": "Tokyo Standard Time"
	},
	"attendees": [
		{
			"emailAddress": {
		        	"address":"user01@YOUR_ACCOUNT.onmicrosoft.com"
      			},
	      		"type": "required"
		},
		{
			"emailAddress": {
				"address":"user02@YOUR_ACCOUNT.onmicrosoft.com"
			},
			"type": "required"
		},
		{
			"emailAddress": {
		        	"address":"room01@YOUR_ACCOUNT.onmicrosoft.com"
      			},
	      		"type": "resource"
		}
	]
}
```

> 2.2.1 と同様に room01 は Outlook のリソースとして登録されているため、"type":"resource" として、いち参加者のように "attendees" に追加しています。ユーザーとして登録されている場合は、"location" のパラメーターで追加します。(詳細は [ドキュメント](https://docs.microsoft.com/ja-JP/graph/api/user-post-events?view=graph-rest-1.0&tabs=http#examples) を参照してください)
> また、日本時間で日時を設定していますが、2.2.1 の Response で取得した結果をそのまま (UTCで) 利用いただいても構いません。

Request URI, Header, Body をコピー＆ペーストしたら、リクエストを送信します。

![20200702_19.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/4a6681b8-e415-4ac4-f6c0-06469da31270.jpeg)

Response 201 (Created) が返ってきたら作成は完了です。

![20200702_20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/0bfa0fe2-0e5b-71fd-7365-ce78a81ee1af.jpeg)

Outlook スケジュールにイベントが作成されているのを確認してください。

![20200702_21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/63580409-bcaf-af2a-35c8-ca4d048bd2d4.jpeg)

> イベントの詳細を開くと、参加者や会議室、件名や説明が入力されているのを確認できます。

![20200702_22.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117583/438dbf51-ec2e-4562-b7fe-9e4636460cd8.jpeg)