フロントエンドのMicrosoft Graphことはじめ
はじめに
使用するライブラリは下記バージョンとなります。
- typescript: 3.5.3
- msal.js : 1.1.3
- @microsoft/microsoft-graph-client : 1.7.0
- @microsoft/microsoft-graph-types: 1.10.0
また、Graph使用部分はAngularになるべく依存しない形で構成していますが
手を抜きたい箇所がちょこちょことあるのでベースは下記Ver.のAngularで作成しています。
- @angular/cli: 8.3.0
- Angular: 8.2.3
それぞれの内容について記事をご覧になるタイミングによっては、画面、仕様が変更されている可能性があるのでご留意くださいませ。
なにがしたいか
フロントエンドだけでMicrosoft Graphから情報取得したい。
以上。
実装
1.Azure AD Applicationの準備
例のごとく、Graphへのアクセストークン取得用のAzure AD Applicationを作成します。
今回はOutlookで管理しているメールの情報などを取得するため
Microsoft個人アカウントにアクセスできるアプリケーションを作成します。
ADアプリを作成する際に「個人アカウント」が使用できるタイプを選択します。
2.ライブラリのインストール
Httpの通信ベースでもGraphからは情報は取得できますが
.net同様公式からClientライブラリが提供されていますので、それを使用します。
インストールするライブラリは下記のとおりです。
msal.js
今回、個人アカウントの情報にアクセスするためAzureAdv2アプリケーションを使用します。
そのためADALではなくMSALを使用します。
Graphにアクセスする際に使用するアクセストークンの取得に使用します。
npm install msal --save
@microsoft/microsoft-graph-client
Microsoft Graphとやり取りすためのライブラリです。
npm install @microsoft/microsoft-graph-client --save
@microsoft/microsoft-graph-types
Clientには型情報がついてこないようです。
TypeScriptを使用している方は@microsoft/microsoft-graph-types
もインストールしておくと
Graphから取得したデータのマッピングが幾分か楽になると思います。
後述するクエリオプションの$select
を使用するのであればいらないかなとは思います。
npm install @microsoft/microsoft-graph-types --save-dev
3. msal.jsのイニシャライズ
Graphからデータを取得するためには、何はともあれアクセストークンを取得する必要があります。
リダイレクト時に読み込まれるページ、あるいはリダイレクト時に読み込まれるJS等でmsalのイニシャライズを行います。
JSでClassを使用している場合はconstructorでイニシャライズを行います。
とにかくリダイレクト時にUserAgentApplication
が生成されるようにしておきます。
import * as msal from 'msal'; export class AuthService { private authClient: msal.UserAgentApplication; constructor() { this.authClient = new msal.UserAgentApplication({ auth: { clientId: '<ADアプリのClientID>', authority: 'https://login.microsoftonline.com/common' } }); } }
UserAgentApplicationのコンストラクタの引数で、使用するAzureADアプリケーションの情報を与えます。
今回Microsoft個人アカウントの情報を取り扱いたいので、authority
はhttps://login.microsoftonline.com/common
を指定します。
テナントに紐づく情報のみに抑えたい場合はhttps://login.microsoftonline.com/<tenant-id>
でOKです。
4. GraphClientのイニシャライズ
先に記述したとおり、Graphからデータを取得するためには
AzureADアプリケーションから提供されるアクセストークンが必要となります。
GraphClientはイニシャライズ時に、Graphアクセス用のトークンを取得するauthProvider
を設定することができます。
Providerを指定せずにGraphアクセス時にヘッダにアクセストークンを設定する事も可能ですが
アクセス都度ヘッダを設定する処理を書くのも邪魔くさいと思うのでProviderを設定するほうがいいかなと思います。
import * as graph from '@microsoft/microsoft-graph-client'; export class GraphService { private client: graph.Client; constructor() { this.client = graph.Client.init({ authProvider: async (done) => { const token = await this.authService.acquireToken({ scopes: [ 'mail.read' ] }); if (token) { done(null, token.accessToken); } else { done('Can not Get Token', null); } } }); } }
authProvider
として、通信を行う際のトークン取得処理を記述します。
3.で設定したmsal.jsのファンクションacquireToken
を使用しアクセストークンを取得します。
acquireTokenの引数で指定するスコープ情報は、使用したいリソースの権限情報をドキュメントで参照してください。
例えば、Messageの権限情報はこちらから参照できます。
acquireToken
はPromiseで値を返却してくれるので、async-awaitでアクセストークンを取得し
authProvider
のCallbackdone
の引数にトークンを指定し実行します。
done
は(error: any, accessToken: string | null)
を引数で実行されるCallbackです。
トークンが取得できなかったりエラーが発生した場合はaccessToken
をnullにし、error
にエラー情報を格納し
逆にトークンが取得できた場合はaccessToken
に取得したトークンを設定し、error
にnullを格納し実行します。
5. Graphの実行
下準備は整いました。GraphClientを使用し、自分に送信されたメールの情報を取得してみようと思います。
export class GraphService { private client: graph.Client; .... getMessage() { this.client.api('/me/messages').get() } }
処理を組み立てるときはMicrosoftのドキュメントにお世話になります。
例えばメッセージを一覧表示する - Microsoft Graph v1.0 | Microsoft Docs
.api()
内のURLの指定は、この「HTTP要求」にあるアドレスを指定すればOKです。
と、いいますか、ページ下部にある例ほぼそのまんまですね。
6. 複数ページにまたがるデータの取得
メールや予定表など、データ数がべらぼうに多そうなデータは一回のリクエストで全件データ取得できません。
あるいは自分で1回あたりの取得データの件数を絞ったりもできます。
アプリで Microsoft Graph データをページングする - Microsoft Graph | Microsoft Docs
その場合、@odata.nextLink
というプロパティに次ページのリンクURLが格納された状態で、Graphからデータが帰ってきます。
なので、全件データを取得したい場合は@odata.nextLink
に、次ページへのリンクが格納されなくなるまでループを回し続けなければならないというわけですね。
private messageList: Message[] = []; /* Message:@microsoft/microsoft-graph-types で提供されている型情報 */ // 初回は「/me/messages」で以降はnextlinkのURLが引数に getMessage(url: string) { this.client.api(url).get().then(x => { (x.value as Message[]).forEach(element => { this.messageList.push(element); }); if (x['@odata.nextLink'] !== '') { const nestNextLink = x['@odata.nextLink']; this.getMessage(nestNextLink); } }); }
7. クエリオプション
特定条件でのデータの絞り込み。取得データを特定の項目のみにする絞り込み等が行なえます。
何が行えるかは下記のドキュメントを参照してください。
クエリ パラメーターを使用して応答をカスタマイズする - Microsoft Graph | Microsoft Docs
その中からいくつかのクエリオプションを見てみます。
$select
取得する項目を指定する事ができます。
通信でどのような項目のやり取りされるかはAPIドキュメントを参照すればOKです。
今回使用してみた/message
のプロパティは下記のドキュメントで確認できます。
メッセージ リソースの種類 - Microsoft Graph v1.0 | Microsoft Docs
このプロパティから取得したい項目を選択することになります。
GraphClientでは.select
がそれにあたります。
下記のように.select
で取得したい項目名を指定します。
export class GraphService { private client: graph.Client; .... getMessage() { this.client.api('/me/messages') .select('subject, receivedDateTime') .get() } }
messageのメール表題のsubject
と受信日時のreceivedDateTime
を取得しています。
$filter
取得する項目の絞り込みを行うことができます。
$select
同様、絞り込む項目はAPIドキュメントを参照します。
GraphClientでは.filter
を下記のように使用します。
filterの論理演算子については下記のドキュメントを参照してください。
クエリ パラメーターを使用して応答をカスタマイズする - Microsoft Graph | Microsoft Docs
export class GraphService { private client: graph.Client; .... getMessage() { this.client.api('/me/messages') .filter('isRead+eq+false') .get() } }
messageの内未読のもののみを取得しています。
まとめ
フロントエンドのみでGraphのデータにアクセスする方法を確認しました。
- Graphへのアクセスは
@microsoft/microsoft-graph-client
を便利に使用しましょう - Graphの使用の仕方は公式ドキュメントが一番参考になります
- クエリオプションを使用してGraphを使いこなしましょう
今回検証に使用したサンプルは下記のリポジトリとなります。