Microsoft Graph を使ってみよう :  基本的な操作

# 基本の 7 操作

Microsoft Graph は多くのリソースにおいて以下の操作をサポートします。

## コレクションの取得
HTTP Get 要求でリソースに対して一覧を取得します。

例)
/users: ユーザーのコレクション
/groups: グループのコレクション

**SDK を使う場合**
コレクションの取得はリソースに対して Request().GetAsync() を実行。

```csharp:C#
await graphClient.Users.Request().GetAsync();
```
## 単一レコードの取得

リソースに対してレコード ID を指定することで単一レコードを取得します。

/users/{id}: 特定のユーザー
/me: サインインしているユーザーの /users/{id} ショートカット

**SDK を使う場合**
単一レコードは ID を指定して実行。

```csharp:C#
await graphClient.Users["レコードのID"].Request().GetAsync();
await graphClient.Me.Request().GetAsync();
```
## レコードの作成
コレクションに対する HTTP Post 要求でレコードが作成できます。

**SDK を使う場合**
リソースに対して Request().AddAsync() メソッドに作成するオブジェクトを渡して実行。

```csharp:C#
await graphClient.Users.Request().AddAsync(user);
```

## レコードの更新

単一レコード URL に対する HTTP Patch 要求で更新します。

**SDK を使う場合**
単一レコードの指定に対して更新するオブジェクトを渡して実行。

```csharp:C#
await graphClient.Users["レコードのID"].Request().UpdateAsync(user);
```

## レコードの削除

単一レコード URL に対する HTTP Delete 要求で削除します。

**SDK を使う場合**
単一レコードの指定に対して、削除を実行。

```csharp:C#
await graphClient.Users["レコードのID"].Request().DeleteAsync();
```

## 関数の実行
Microsoft Graph では関数のアドレスに HTTP Post 要求を送信することで、メールを送信するなど操作を実行することが出来ます。

例)
/me/messages/{id}/send: メール送信
/me/messages/{id}/move: メールの移動

**SDK を使う場合**
操作を行う単位に対してメソッドを実行。

```csharp:C#
graphClient.Me.Messages["id"].Send();
graphClient.Me.Messages["id"].Move("another folder");
```
## バッチ処理
$batch URL に HTTP Post 要求を送信することで複数の要求をバッチ処理できます。

POST https://graph.microsoft.com/v1.0/$batch

```json:Body
{
  "requests": [
    {
      "id": "1",
      "method": "GET",
      "url": "/me/drive/root:/{file}:/content"
    },
    {
      "id": "2",
      "method": "GET",
      "url": "/me/planner/tasks"
    },
    {
      "id": "3",
      "method": "GET",
      "url": "/groups/{id}/events"
    },
    {
      "id": "4",
      "url": "/me",
      "method": "PATCH",
      "body": {
        "city" : "Redmond"
      },
      "headers": {
        "Content-Type": "application/json"
      }
    }
  ]
}
```

**SDK を使う場合**
現時点ではまた C# 用のライブラリには実装されていないようです。

### 制限

- ネストされたバッチ要求はサポートされません
- すべての要求は同期で実行されます
- トランザクションはサポートされません
- 最大 20 要求を処理できます

# 基本の 7 クエリ

Microsoft Graph では多くのリソースにおいて、以下の OData クエリをサポートします。

## SELECT クエリ

OData の Select クエリをサポートしているため、以下のようなクエリをかけます。

/users?$select=displayName,jobTitle,userPrincipalName
<img width="678" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/71fcb7e8-6201-36d4-112e-37326c190417.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Users.Request().Select("displayName,jobTitle").GetAsync();
```
## FILTER クエリ

レコードのフィルタリングを行うことが出来ます。

/users?$filter=startswith(mail, 'admin')
<img width="660" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/95d66e11-290e-6fd5-c85e-8fa767e498af.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Users.Request().Filter("startswith(mail,'admin')").GetAsync()
```

## ORDERBY クエリ

レコードの慣れべ替えを行います。

/users?$orderby=displayName
<img width="665" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/11e658ca-d806-2686-4966-d963a7f17709.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Users.Request().OrderBy("displayName").GetAsync()
```

## TOP クエリ

上位 x 件のレコードを取得する場合は、TOP クエリが利用できます。以下の場合、上位 1 件を取得していますが、結果はコレクションとして返ります。

/users?$top=1
<img width="664" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/6e1d20fa-f213-2298-62a7-ae822da6e3a4.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Users.Request().Top(1).GetAsync();
```
### SKIP クエリ

手動ページングをしたい場合などに、レコードを x 件スキップすることが出来ます。リソースによってはサポートされません。TOP クエリと一緒に使われることが多いです。

/me/mailFolders?$top=1&$skip=1
<img width="675" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/daad45f2-63b7-e2da-b4f0-f6c2ee516d0e.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Me.MailFolders.Request().Top(1).Skip(1).GetAsync();
```

## EXPAND クエリ

関連リソースをメインのリソースと同時に展開して取得します。

/me/drive/root?$expand=children
<img width="674" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/a526bb98-8ac4-3cb4-2f13-c7710fb28f67.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Me.Drive.Root.Request().Expand("children").GetAsync();
```

## SEARCH クエリ

FILTER クエリと似ていますが、検索キーワードで検索が行えます。現在は以下のリソースで実行可能です。

- 人物コレクション
- メールコレクション

メールについては Outlook の検索でも利用できる、キーワード クエリ言語 (KQL) 構文で検索を実行できます。

me/messages?$search="from:manager1@graphdemo01.onmicrosoft.com"

**SDK を使う場合**

Search メソッドが存在するはずですが、現在の SDK に見当たらなったため、QueryOption で実行。検索文字列をダブルクォーテーションで囲む場合、エスケープしてください。

```csharp:C#
var users = await graphClient.Me.Messages.Request(
    new List<Option>() {
        new QueryOption("$search", "\"from:manager1@graphdemo01.onmicrosoft.com\"")
    }).GetAsync();
```



## COUNT クエリ

レコードの総数を確認したい場合、COUNT クエリを使います。リソースによってはサポートされません。

/me/mailFolders?$count=true
<img width="640" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/6b2478e2-2cb5-7790-5917-785a66903b0b.png">

**SDK を使う場合**

```csharp:C#
await graphClient.Me.MailFolders.Request(new List<QueryOption>()
    {　new QueryOption("$count", "true") }).GetAsync();
```

# Tips

Microsoft Graph を使う上でいくつか Tips を紹介します。

## リレーションシップを使ったナビゲーション

Microsoft Graph は関連を辿ったレコードの取得が可能です。例えば自分のマネージャーは以下のパスで取得できます。

/me/manager
<img width="669" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/7a19304b-1802-5261-df19-0d12c1951084.png">

**SDK を使う場合**

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

## ID で特定レコードを取得

コレクションで返る場合、ID を指定することで単独レコードとして取得が可能です。ID はリソースによって形式が異なります。

/users/<id>: id で指定したユーザーのレコードのみが返る
<img width="684" alt="Capture.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/214116/914ee13c-b90d-4bd1-fc58-9a629fcdd4e6.png">

**SDK を使う場合**

```csharp:C#
var user = await graphClient.Users["6746d79d-8c77-4eec-a61f-cce6beb162f7"].Request().GetAsync();
```

## ページング

レコードが一度のクエリで取得しきれない場合、ページング情報が応答に含まれます。すべてのレコードを取得する場合は、継続してページングリンクにアクセスして情報を取得します。@odata.nextLink にページング用のアドレスが含まれます。

## メタデータ

Microsoft Graph ではリソースのクエリだけでなく、メタデータを取得することも出来ます。

**Microsoft Graph API v1.0 メタデータ**
https://graph.microsoft.com/v1.0/$metadata

**Microsoft Graph API beta メタデータ**
https://graph.microsoft.com/beta/$metadata

## Open API 定義

上記メタデータ以外に、Open API (旧Swagger) をサポートします。現在はまだ GitHub で公開されているだけですが、将来的にはサービスに組み込まれる予定です。

[Microsoft Graph OpenAPI v3.0.1 description (preview)](https://github.com/microsoftgraph/microsoft-graph-openapi)

## 要求の同時実行制限

Microsoft Graph の同時呼び出しが多すぎた場合、リクエストがスロットリングで調整される場合があります。その際は HTTP ステータスコード 429 (Too many requests) が返るため、あらかじめ数秒待機後にリトライする処理を入れるようにしてください。その他のエラーについては [Microsoft Graph のエラー応答とリソースの種類](https://developer.microsoft.com/ja-jp/graph/docs/concepts/errors) を参照。

## データの差分取得
いくつかのリソースでは前回データ取得時からの変更だけが取得できる機能があります。次回詳細を見ていきます。

## 変更通知
いくつかのリソースでは、Webhook を使った変更通知を受け取れます。こちらも今後の記事で詳細を紹介します。

# まとめ

まず基本的な操作をおさえることで、より効率の良い開発が行えるようになります。是非導入してください。

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

# 参照
[Microsoft Graph API を使用する](https://developer.microsoft.com/ja-jp/graph/docs/concepts/use_the_api)
[クエリ パラメーターを使用して応答をカスタマイズする](https://developer.microsoft.com/ja-jp/graph/docs/concepts/query_parameters)
[Microsoft Graph スロットリングについて](https://developer.microsoft.com/ja-jp/graph/docs/concepts/throttling)
[Microsoft Graph に関する既知の問題](https://developer.microsoft.com/ja-jp/graph/docs/concepts/known_issues)
[Microsoft Graph のエラー応答とリソースの種類](https://developer.microsoft.com/ja-jp/graph/docs/concepts/errors)
[Microsoft Graph OpenAPI v3.0.1 description (preview)](https://github.com/microsoftgraph/microsoft-graph-openapi)
[Best Practices when using Microsoft Graph APIs platform capabilities (英語動画)](https://www.youtube.com/watch?v=XDzBMvcEj30)