Microsoft Graph REST APIで、OneDrive内にあるはずのファイルにアクセスできなくて困った話

訳あってMicrosoft Graphについていろいろ調べてます。

最終的なゴールは、「Microsoft Graph API経由で、OneDrive上にあるエクセルファイルのセルを更新し、計算結果を取得したい」です。

今回は、そもそもMicrosoft GraphのAPIでエクセルファイルにアクセスできなくて苦労した話。

# まずはチュートリアル
Microsoft Graphを使うのは初めてなので、[この辺の](https://docs.microsoft.com/ja-jp/graph/use-postman?context=graph/api/1.0)チュートリアルで基本を学習。
後々の実装を考慮してPostmanを使うチュートリアルを選びました。

チュートリアルの内容はざっくり

- Microsoft GraphのPostmanコレクションを、Postmanのローカルワークスペースに落とす
- Azure AD Portalで、新規のアプリを登録する
- Azure AD Portalで、APIのアクセス許可を設定
- Postman内で、認証情報を環境変数に登録
- Postmanで、認証を要求してトークンをゲット
- Postmanで、ユーザープロフィールやメールの情報を取得するリクエストを実行

といった感じでした。

# チュートリアルでハマったポイント
Microsoft Graph APIには、Microsoftユーザーの委任が必要な機能と、ユーザー委任が要らない機能があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/15553c0c-6e80-cf75-7a28-df82d41df537.png)
委任が必要な機能は**Delegated**配下にあり、委任が要らない機能は**Application**配下に入っているようです。

利用価値が高い機能は、だいたいDelegatedの方に入っている印象です。

Delegatedの機能を使おうとして、ブチ当たった権限関係の壁が以下。

## 試行① 個人アカウントではダメだった
最初は自分の個人Microsoftアカウントを使おうとしてましたが

- Azure ADにアプリを登録するところまではOK
- でもPostman側で認証が通らずトークンがゲットできなかった

です。
## 試行② 使いたいAPIによっては管理者権限がないとダメ
では、と会社のADアカウントでテストしようとしたらトークンはゲットできたが・・・
Azure AD Portal内でAPIのアクセスを許可する際、APIによっては管理者の承認が必要です。

今回のチュートリアルで使う**User.Read.All**へのAPIアクセスを許可するには管理者承認が必要。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/d99e2faa-183e-221c-4816-c9605a884d44.png)
だが、私のADユーザーは管理者権限がないので、上図の**Grant admin consent for xxx**がグレーになっていてクリックできなかった。

ので、**しょうがないからビジネスアカウントを開設しました**。。
（$5.00/ユーザ/月で、1ヶ月の無料トライアルあり）
ビジネスアカウントで全部の設定をやり直したら無事にチュートリアルの例をクリアできました。

# いよいよエクセルのファイルにアクセス
要領が掴めた気がしたので、次の課題はこれ。
Excel のブックとグラフの API の概要：
https://docs.microsoft.com/ja-jp/graph/excel-concept-overview

API越しでエクセルファイルにアクセスしたいので、OneDriveのルートディレクトリにtestfile.xlsxというファイルをアップロードしました。

## OneDriveにアップしたはずのファイルが見つからない問題
Microsoft Graph REST API v1.0の[リファレンス](https://docs.microsoft.com/ja-jp/graph/api/resources/excel?view=graph-rest-1.0)によれば、ワークブックにアクセスするにはDrive APIを使うそうです
`https://graph.microsoft.com/v1.0/me/drive/items/{id}/workbook/`

が、ファイルのIDがわからないので、とりあえずOneDrive内のファイルリストを取得してみよう
GET `https://graph.microsoft.com/v1.0/me/drive/root/children`

・・・

```
{
    "error": {
        "code": "itemNotFound",
        "message": "Item not found",
        "innerError": {
            "date": "2021-09-02T08:56:26",
            "request-id": "08062f98-ab36-46d8-b6ee-3c5e6eeb0904",
            "client-request-id": "ebae23aa-f7c1-655d-08c9-355f218a0bb0"
        }
    }
}
```

**・・・Item not found だと？！**

ファイルがちゃんとアップロードされてなかったんじゃないかとか、API URLのパス指定が違うんじゃないかとか、いろいろ疑った末、最終的に答えをくれたのはこちらのページ：
https://stackoverflow.com/questions/57991060/cannot-access-me-drive-root-children-nor-any-driveitem-object

問題は、DelegatedのAuthorization設定で、Scopeがデフォルト値のままになっていたことでした。

デフォルト値の`https://graph.microsoft.com/.default`を、今回使うAPIに設定した権限：`files.readwrite.all`に変更したら問題が解決しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/3dd423ec-e9c2-79c1-7962-bf8051f966e1.png)

無事にOneDrive内のファイルリストがゲットできるようになったところで本日は終了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308847/8a1b76cc-c46f-86e3-2cfb-82e8621b6626.png)

次はエクセルファイル内のセルの値の更新をテストする予定。