Microsoft Graph を使ってみよう : 拡張

# 拡張を利用するシナリオ

Microsoft Graph は Azure AD や Office 365 といった、社内の情報が集約されている場所です。そこに独自のデータを含めることにより、それらの情報も一元的に管理が行え、複数の場所から同じ手法でアクセスできるようになります。

例えば以下のようなシナリオがあります。

- 追加のユーザープロファイル
- 社内アプリケーションで使う設定やデータ
- レポートで活用できる独自のデータ

# 拡張の種類

Microsoft Graph には 2 種類の拡張方法があります。

**オープン拡張**
スキーマを持たないデータを格納できます。簡単なデータを持たせるのに最適です。

**スキーマ拡張**
型指定されたデータを格納できます。スキーマがあるため、フィルターなども利用することが出来ます。

それぞれの拡張がサポートされるリソースは、現時点では以下の通り。

| リソース	| オープン拡張機能	| スキーマ拡張機能 |
|:--|:----|:----|
| 管理単位	| プレビューのみ	| プレビューのみ |
| 予定表イベント	| GA	| GA |
| デバイス	| GA	| GA |
| グループ	| GA	| GA |
| グループ予定表イベント	| GA	| GA |
| グループ会話の投稿	| GA	| GA |
| メッセージ	| GA	| GA |
| 組織	| GA	| GA |
| 個人用連絡先	| GA	| GA |
| ユーザー	| GA	| GA |

随時更新されるため、利用する際に [サポートされているリソース](https://developer.microsoft.com/ja-jp/graph/docs/concepts/extensibility_overview#supported-resources) を参照。

# オープン拡張を試す

ここでは独自アプリで使うためのローミングプロファイル情報を、ユーザーに格納してみます。
また名前を固有にするために "com.onmicrosoft.graphdemo01.roamingSettings" という名前を使います。

1\. Graph エクスプローラーにアクセスして、組織アカウントでサインイン。POST メソッドで以下のようにリクエストを作成して実行。

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

```json:Body
{
    "@odata.type":"microsoft.graph.openTypeExtension",
    "extensionName":"com.contoso.roamingSettings",
    "theme":"dark",
    "color":"purple",
    "lang":"Japanese"
}
```

2\. 追加した情報を取得するために、以下クエリを実行。select クエリに id を含め、かつ $expand=extensions の指定で情報が取得可能。

GET: https://graph.microsoft.com/v1.0/me?$select=id,displayName&$expand=extensions

```json:応答

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,extensions)/$entity",
    "id": "6746d79d-8c77-4eec-a61f-cce6beb162f7",
    "displayName": "中村 憲一郎",
    "extensions@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('6746d79d-8c77-4eec-a61f-cce6beb162f7')/extensions",
    "extensions": [
        {
            "@odata.type": "#microsoft.graph.openTypeExtension",
            "theme": "dark",
            "color": "purple",
            "lang": "Japanese",
            "extensionName": "com.contoso.roamingSettings",
            "id": "com.contoso.roamingSettings"
        }
    ]
}
```

3\. 拡張名を指定して DELETE を実行すると削除可能。

DELETE https://graph.microsoft.com/v1.0/me/extensions/{name}

<img width="708" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/33bffe12-dcd4-3e0b-d02c-90c2693d68bb.png">

4\. 他のユーザーの情報を格納する場合、以下のようにアドレスを /users/<id> に変更。

POST: https://graph.microsoft.com/v1.0/users/{id}/extensions

<img width="705" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/8bbd5cbf-7e58-bf7c-dcc2-444c6fe5bdb1.png">

5\. 結果を確認。

https://graph.microsoft.com/v1.0/users?$select=id,displayName&$expand=extensions
<img width="677" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/ea1c1908-000d-1df5-cbdd-9a9833e5bab5.png">

**SDK を使う場合**

オープン拡張の追加

```csharp:C#
var openTypeExtension = new OpenTypeExtension()
{
    ExtensionName = "com.onmicrosoft.graphdemo01.roamingSettings",
    AdditionalData = new Dictionary<string, object>()
    {
        { "theme","dark"},
        { "color", "purple"},
        { "lang","Japanese"}
    }
};

var openExtensionResponse = await graphClient.Me.Extensions.Request().AddAsync(openTypeExtension);
```

拡張データの取得

```csharp:C#
await graphClient.Me.Extensions.Request().GetAsync();
```

<img width="641" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/80bd6ea0-44d2-1dfd-d84b-29f32a198c3d.png">

拡張の削除

```csharp:C#
await graphClient.Me.Extensions[openExtensionResponse.Id].Request().DeleteAsync();
```

# スキーマ拡張を試す

スキーマ拡張は現在 Graph エクスプローラーからは試せないため、C# のプログラムを使って試します。以下のスキーマ拡張を追加します。

- User リソースに対して追加
- myextension という名前を利用

1\. まず拡張用のクラスを定義。

```csharp:C#
public class schemaExtentionClass
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
}
```

2\. 次にスキーマ拡張を作成。

```csharp:C#
SchemaExtension extensionDefinition = new SchemaExtension()
{
    Description = "My first extension",
    Id = $"myextension",
    Properties = new List<ExtensionSchemaProperty>()
    {
        new ExtensionSchemaProperty() { Name = "id", Type = "Integer" },
        new ExtensionSchemaProperty() { Name = "name", Type = "String" }
    },
    TargetTypes = new List<string>()
    {
        "User"
    }
};

SchemaExtension schemaExtension = await graphClient.SchemaExtensions.Request().AddAsync(extensionDefinition);
Console.WriteLine(schemaExtension.Id);
```

3\. プログラムの実行後、Id を確認。

<img width="848" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/2d5ed928-3dd0-d8e6-a21b-126d6bc8d781.png">

4\. 拡張ができたら Graph エクスプローラーに戻って、自分のユーザーに PATCH を実行。

<img width="430" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/0e8b9c37-cb75-232f-88bb-4c6ce46ef03e.png">

5\. 以下のクエリで結果を確認。

GET: https://graph.microsoft.com/v1.0/me?$select=id,displayName,exthejv6jgb_myextension
<img width="679" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/2f65085e-f8a7-e6a2-a726-ec1c3143fafd.png">

6\. 拡張名を指定して DELETE を実行すると削除。

DELETE: https://graph.microsoft.com/v1.0/schemaExtensions/exthejv6jgb_myextension
<img width="611" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/cddeb820-3c81-8d65-e3c4-14801e9f0ff1.png">


データの追加、取得、削除は SDK でも当然実行できます。

User オブジェクトの AdditionalData に追加。

```csharp:C#
var me = await graphClient.Me.Request().GetAsync();
me.AdditionalData = new Dictionary<string, object>()
{
    { schemaExtension.Id, new SchemaExtentionClass() {  Id = 123, Name = "123"} }
};

await graphClient.Me.Request().UpdateAsync(me);
```

明示的にスキーマ拡張 ID を指定して取得。

```csharp:C#
me = await graphClient.Me.Request().Select(schemaExtension.Id).GetAsync();
```

<img width="588" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/827872f4-687c-ab5d-7b89-a91cf1d8ace4.png">

ID を指定して削除

```csharp:C#
await graphClient.SchemaExtensions[schemaExtension.Id].Request().DeleteAsync();
```

# まとめ
拡張機能が使えることで、既存のデータのやり取りだけではなく、独自データを格納できるデータベース的な使い方が出来るようになりました。新規のリソースは作れませんが、関連しそうなデータを入れて活用してください。

[目次へ戻る](https://qiita.com/kenakamu/items/6a1ca508dc093779eefa)

# 参照
[拡張機能を使用してカスタム データをリソースに追加する](https://developer.microsoft.com/ja-jp/graph/docs/concepts/extensibility_overview)
[オープン拡張機能の使用 (例)](https://developer.microsoft.com/ja-jp/graph/docs/concepts/extensibility_open_users)
[スキーマ拡張機能の使用 (例)](https://developer.microsoft.com/ja-jp/graph/docs/concepts/extensibility_schema_groups)