はじめに
MS365のGraph APIを使ってユーザー検索を行いたかったけど地味にハマったのでまとめました。
やりたかったこと
Azure ADに登録されているユーザーの中から
特定の「companyName(会社名)」でfilterして
そこから「displayName」で検索した結果を表示する。
Graph Explorer で試してみる
公式ドキュメント見ながらクエリの使い方を調べつつ
上記のGraphExplorerで実行してみる。
右上のアカウントアイコンからサインインすれば自分が使用しているAADテナント内で実際にAPIの実行が行えるので
めちゃめちゃ便利です。
実行したリクエスト
https://graph.microsoft.com/v1.0/users?$filter=companyName eq 'Qiita' &$search="displayName: nami"
上記のリクエストで会社名が「Qiita」の中からdisplayNameが 「nami」であるオブジェクトを検索します。
上記のリクエストをgraph Explorer上で実行すると
{
"error": {
"code": "Request_UnsupportedQuery",
"message": "Request with $search query parameter only works through MSGraph with a special request header: 'ConsistencyLevel: eventual'",
"innerError": {
"date": "2023-09-02T10:28:45",
"request-id": "7389c0cf-fe86-468c-9e3d-d76526cefb24",
"client-request-id": "7389c0cf-fe86-468c-9e3d-d76526cefb24"
}
}
}
上記の様なレスポンスが返ってきて正しくオブジェクトが取得できませんでした。
原因
レスポンスのメッセージに
「Request with search query parameter only works through MSGraph with a special request header: 'ConsistencyLevel: eventual'」
と書かれている通り
$searchクエリパラメータを持つリクエストは、特別なリクエストヘッダ: 'ConsistencyLevel: eventual'を付与する必要があるみたいです。
こんな感じでリクエストヘッダーを付与してあげます。
するとうまく該当のオブジェクトを取得できました。
なぜ必要?
GraphAPIで高度なクエリを実行する場合に必要みたいです。
何が高度なクエリになるのかは以下の公式ドキュメントで確認してください。
今回のケースではsearchを使うために必要だったみたいです。
ConsistencyLevel: eventual が何者かについてはchatGPTがわかりやすく教えてくれました。
ConsistencyLevel: eventualが必要とされるのは、Microsoft Graph APIの特定の操作において、データの一貫性を確保するためです。具体的には、以下のシナリオや理由が考えられます:
分散データベースの性質: Microsoft Graph APIの背後には、分散データベースやストレージシステムが存在します。これらのシステムでは、データは複数の場所やノードにコピーされることが一般的です。このような環境では、すべてのノードが同時に更新されることは難しく、一貫性の確保が課題となります。
search クエリパラメータ: Microsoft Graph APIでの検索操作($searchクエリパラメータを使用するもの)は、特にデータの一貫性に関する要件が厳しいです。これは、検索インデックスやキャッシュが関与するため、最新のデータがすぐには反映されない可能性があるからです。
パフォーマンスと一貫性のトレードオフ: ConsistencyLevel: eventualを指定することで、クライアントは最終的な一貫性を受け入れることを示します。これにより、APIは高速なレスポンスを提供できる一方、データが最新であることは保証されません。これは、パフォーマンスと一貫性の間のトレードオフとして考えることができます。
明示的な一貫性の指定: 一部のAPI操作では、クライアントが期待する一貫性のレベルを明示的に指定することが求められます。これにより、クライアントとサーバーの間での期待値の不一致や誤解を防ぐことができます。
要するこのリクエストヘッダーはGraphAPIの特定の操作(特に検索操作)の際にデータが最新じゃない可能性がある
ことを承知してます!!って宣言するために付与するものらしいです。
勉強になりますね。
補足情報
companyNameの取得にはUser.Read.Allのパーミッションが必要です。
ちなみに
複数の検索条件でどれかにマッチしたオブジェクトを取得したい場合は以下のように記述します
https://graph.microsoft.com/v1.0/users?$filter=companyName eq 'Qiita' &$search="displayName: nami" OR "mail:nami"
上記のリクエストだと
会社名 Qiitaの中からsidplayNameに「nami」 を含む、またはmailに「nami」を含むオブジェクトを検索します。
まとめ
Graph API面白いですね。