Microsoft Graph で Microsoft Todo の CRUD

プライベートで使っている Todo アプリを、Todoist から Microsoft Todo に移行しようかと検討中。もし移行するとなると、リストやタスクを入力し直すのは面倒だ。移行用にプログラム書きたいところ。

Microsoft Todo なら、Microsoft Graph という RESTful API を使えば CRUD できそうだった。SDK もあるところは流石。

docs.microsoft.com

Python ではあるけど、Microsoft Graph を使って Microsoft Azure の情報を取得する記事はあった。

dev.classmethod.jp

自分の場合は C# だし、Microsoft Azure には既にサインアップ済なので、Azure Active Directoy にアプリを登録するところからスタート。

注意点として、一般に公開するアプリの場合は、「サポートされているアカウントの種類」を「任意の組織ディレクトリ内のアカウント(任意の Azure AD ディレクトリ - マルチテナント)と個人の Microsoft アカウント(SkypeXboxなど)」にしておく必要がありそうだった。

.NET 用の SDK は NuGet からインストール。

www.nuget.org

OAuth で使うパッケージも併せてインストール。

www.nuget.org

Microsoft Todo のリストとタスクを CRUD するサンプルを書いてみた。

using Azure.Identity;
using Microsoft.Graph;

// Microsoft Todo のタスクとリストを CRUD するには
// Tasks.ReadWrite の許可が必要。
var scopes = new[]
{
    "Tasks.ReadWrite",
};

// 一般ユーザーの Microsoft Todo にアクセスするときは
// common を指定すれば良いみたい。
var tenantId = "common";

// Azure AD で登録したアプリケーションの ID (Client ID)
var clientId = "YOUR_CLIENT_ID";

// Web ブラウザを表示して、
// ユーザーに Microsoft アカウントにログインしてもらえるよう、
// GraphServiceClient を構成する。
// 最初に API を呼び出すタイミングでブラウザが起動する。
var options = new InteractiveBrowserCredentialOptions
{
    TenantId = tenantId,
    ClientId = clientId,
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    RedirectUri = new Uri("http://localhost"),
};
var interactiveCredential = new InteractiveBrowserCredential(options);
var graphClient = new GraphServiceClient(interactiveCredential, scopes);

// リスト一覧表示
var todoLists = await graphClient.Me
    .Todo
    .Lists
    .Request()
    .GetAsync();
foreach (var todoList in todoLists)
{
    Console.WriteLine($"既存のリスト:{todoList.DisplayName}");
}

// リスト登録
var createdList = await graphClient.Me
    .Todo
    .Lists
    .Request()
    .AddAsync(new TodoTaskList
    {
        DisplayName = "Test List",
    });
Console.WriteLine($"登録したリスト:{createdList.DisplayName}");

// タスク登録
var createdTask = await graphClient.Me
    .Todo
    .Lists[createdList.Id]
    .Tasks
    .Request()
    .AddAsync(new TodoTask
    {
        Title = "Test Task",
    });
Console.WriteLine($"登録したタスク:{createdTask.Title}");

// リスト内のタスク一覧表示
var tasks = await graphClient.Me
    .Todo
    .Lists[createdList.Id]
    .Tasks.Request()
    .GetAsync();
foreach (var task in tasks)
{
    Console.WriteLine($"{createdList.DisplayName}:{task.Title}");
}

// タスク更新
createdTask.CompletedDateTime = DateTimeTimeZone.FromDateTimeOffset(DateTimeOffset.Now);
var updatedTask = await graphClient.Me
    .Todo
    .Lists[createdList.Id]
    .Tasks[createdTask.Id]
    .Request()
    .UpdateAsync(createdTask);
Console.WriteLine($"更新したタスク:{updatedTask.Title}");

// タスク削除
await graphClient.Me
    .Todo
    .Lists[createdList.Id]
    .Tasks[updatedTask.Id]
    .Request()
    .DeleteAsync();
Console.WriteLine($"削除したタスク:{updatedTask.Title}");

// リスト更新
createdList.DisplayName = "Test Updated List";
var updatedList = await graphClient.Me
    .Todo
    .Lists[createdList.Id]
    .Request()
    .UpdateAsync(createdList);
Console.WriteLine($"更新したリスト:{updatedList.DisplayName}");

// リスト削除
await graphClient.Me
    .Todo
    .Lists[updatedList.Id]
    .Request()
    .DeleteAsync();
Console.WriteLine($"削除したリスト:{updatedList.DisplayName}");

Console.ReadLine();

.NET 6 で実行。自分個人の Microsoft アカウントで試してみた。

まだたいしたリストは登録してなかったけど、一応自分のリスト一覧が表示できていた。CRUD も成功。ただ、SDKAPI にクセがあったな。