SharePointのAPIからファイル情報を取得したり、ファイルをダウンロードする。
簡単そうなことなのに、いかんせん情報が少なかったりガセネタばかりで手こずったので、ここに詳しく記録しておく。
前提条件確認、下準備
仮に、テナント名を{{MYTENANT}}、サイト名を{{MYSITE}}としよう。
ブラウザでSharePointの画面を閲覧する際は以下のようなURLになる。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}
「ドキュメント」をクリックすると以下のようなURLに飛ぶ。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/Shared%20Documents/Forms/AllItems.aspx
「Shared Documents」がURLエンコードされて「Shared%20Documents」である。
このディレクトリはどのサイトにもあるだろう。
サンプルとして、以下のような階層でサブディレクトリとファイルを作成した。
Shared Documents/TestFolder/Book1.xlsx
APIのURL確認
ためしにブラウザで以下のようなURLにアクセスするとXMLで応答がある。
・フォルダ情報
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents')
・サブフォルダ一覧
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents')/Folders
・フォルダ内のファイル一覧
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents%2FTestFolder')/Files
なお、引数の値は相対パスで書くと
'Shared%20Documents'
で始まるが、絶対パスでは
'%2Fsites%2F{{MYSITE}}%2FShared%20Documents'
のように書く(「%2F」は「/」のこと)。
GetFolderByServerRelativeUrlの引数は相対パスでも問題ないようだが、GetFileByServerRelativeUrlによるファイルダウンロードの場合は絶対パスを指定しないと応答が返らなかった。
・ファイルダウンロード
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_api/web/GetFileByServerRelativeUrl('%2Fsites%2F{{MYSITE}}%2FShared%20Documents%2FTestFolder%2FBook1.xlsx')/$value
ファイルダウンロードの引数に相対パスを渡した場合、以下のようなメッセージが返った。
serverRelativeUrlParameter name: 指定した値は serverRelativeUrl パラメーターではサポートされていません。
APIに関するマイクロソフトの公式ドキュメントは以下にある。

API実行用アプリケーションの登録
以下のようなURLでアプリケーション登録用の画面が表示される。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_layouts/15/appregnew.aspx
※一度作成したアプリケーションの更新・削除方法が不明なので、まず適当な値を入れてお試しするのが吉。
・クライアントID:「生成」ボタンを押せば勝手に生成される。
・クライアントシークレット:「生成」ボタンを押せば勝手に生成される。
・タイトル:任意のアプリケーション名を入力する。
・アプリドメイン:任意のドメインを入力する。「localhost」などでもよいようだ。
・リダイレクト先のURI:「http://localhost」など。
「作成」を実行すると、「アプリ ID が正常に作成されました。」という画面に遷移する。
この画面に表示されている情報を大切に保管する。
アプリケーションへの権限付与
以下のようなURLでアプリケーションへの権限付与用の画面が表示される。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_layouts/15/appinv.aspx
・アプリID:先ほど作成したアプリケーションの「クライアントID」を入力する。
「参照」ボタンを押すと、その他の項目が補完される。
・アプリの権限要求XML:以下のような値を入れる。
<AppPermissionRequests>
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
</AppPermissionRequests>
【参考】公式サイトの説明。よくわからない。

アプリの権限画面にてREALMを確認
以下のようなURLでアプリの権限が表示される。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_layouts/15/appprincipals.aspx
アプリIDという欄に、先程のクライアントIDの後ろに「@」で区切られてハイフン区切りの36文字の文字列が続いている。この36文字がREALMである。コピーして保管する。
API実行
いよいよ、アプリからAPIを実行してみる。
APIの実行は
・アクセストークン取得
・SharePointAPI実行
の2段階の手続きを踏む必要がある。
アクセストークンの有効期限は約8時間後。一度取得すれば期限が来るまでSharePointAPI実行を繰り返すことができる。
アクセストークン取得
ここまでで取得した各値を使い、以下のようなリクエストを送信する。
・URL: https://accounts.accesscontrol.windows.net/{{REALM}}/tokens/OAuth/2
・POSTリクエスト
・HTTPヘッダに「Content-Type: application/x-www-form-urlencoded」
・リクエストボディは以下のパラメータをセットする。
grant_type=client_credentials
client_id={{クライアントID}}@{{REALM}}
client_secret={{クライアントシークレット}}
resource=00000003-0000-0ff1-ce00-000000000000/{{MYTENATNT}}.sharepoint.com@{{REALM}}
※「00000003-0000-0ff1-ce00-000000000000」はSharePointを示すprincipalという値らしい。
※Postmanなどのツールを使う場合は気にしなくてもよいが、curlなどで送信する場合は「@」や「/」をURLエンコードして「name=value&name=value&…」の形式でボディを作る。
「@」→「%40」、「/」→「%2F」である。
クライアントシークレットにも「/」や「=」が入っているので、忘れずにURLエンコードを行う。
※「{{MYTENANT}}.sharepoint.com」の部分を間違うと後のSharePointAPI実行で以下のようなエラーが返る。これにしばらく嵌って時間を浪費した。
{"error_description":"Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."}
うまくいけばJSONで応答が返ってくる。「access_token」に入っている値(長ーい文字列:これがアクセストークン)を抽出する。
SharePointAPI実行
・URL: なんでもよい。さっきブラウザで実行したAPIのURLから適当にピックアップした。
https://{{MYTENANT}}.sharepoint.com/sites/{{MYSITE}}/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents')
・(上のURLの場合は)GETリクエスト
・HTTPヘッダに「Authorization: Bearer {{アクセストークン}}」
・HTTPヘッダに「Accept: application/json;odata=nometadata」
うまくいけば、欲しかった情報が返ってくるはず。
以上
【参考サイト】
