記事内に広告が含まれています

【ASP.NET Core】Azure Cosmos DBと連携したWeb APIを作成する

C#

ASP.NET Core Web API(C#)とAzureのNoSQLサービスであるAzure Cosmos DBを使って、シンプルなAPIを作成する方法を解説します。

本記事は以下の公式チュートリアルをベースに作成しています。

チュートリアル: Azure Cosmos DB for NoSQL で ASP.NET Web アプリケーションを開発する
ASP.NET チュートリアルでは、Azure Cosmos DB for NoSQL からデータを照会する Web アプリケーションを作成します。

環境

  • Visual Studio 2022
  • .NET 6

前提

  • Azureアカウントが作成済みであること

Azure Cosmos DBアカウントの作成

まずCosmos DB(Freeプラン)のアカウント作成方法について説明します。
既に作成済みの場合は飛ばしてください。

Azureポータルを開き、上部の検索窓に「cosmos」と入力すると、検索結果に「Azure Cosmos DB」が表示されるのでクリックします。

左上の「作成」をクリックします。

複数のAPIが表示されますが、今回は「コア (SQL) – 推奨」を選択します。

赤枠部分を入力後、「レビュー + 作成」をクリックします。

※主な設定項目の説明

  • サブスクリプション:使用したいサブスクリプションを選択します。
  • リソースグループ:任意の名前で新規作成します。作成済みのリソースグループがある場合はそれを選択してもOKです。
  • アカウント名:任意の名前を設定します。
  • 場所:日本国内の場合は一般的に「Japan East」か「Japan West」を選択します。
  • Freeレベル割引の適用:一定の範囲まで無料で使えるので必ず「適用」(デフォルト)にしましょう。
    ※Freeレベルは1つのAzure サブスクリプションで1つまでしか適用できないので注意

その他の設定についてはデフォルトのままで大丈夫です。

問題がなければ「作成」をクリックします。完了するまで数分待ちましょう。

作成が完了したら、「リソースに移動」をクリックします。

メニューの「キー」からURIとプライマリキーを確認します。これらは後に使用します。

ASP.NET Core Web APIの作成

それではAPIを作成していきましょう。今回はTodoアイテムを管理するシンプルなAPIを作成します。

プロジェクトの作成とパッケージのインストール

Visual Studioを開き、ASP.NET Core Web APIプロジェクトを作成します。

今回は「CosmosTodoApi」という名前で作成していますが、プロジェクト名はなんでもOKです。

Swaggerは使用しないため「Open API サポートを有効にする」のチェックは外しましょう。

プロジェクトが作成できたら、Cosmos DBとの連携に必要なパッケージをインストールします。

プロジェクト名を右クリック→「Nuget パッケージの管理」からNuget パッケージマネージャーを開き、「Microsoft.Azure.Cosmos」をインストールします。

モデルの作成

まずTodoItemモデルを作成します。
プロジェクトの直下に「Models」というフォルダを作成し、その中に「TodoItem.cs」を追加してください。

using Newtonsoft.Json;

namespace CosmosTodoApi.Models
{
    public class TodoItem
    {
        [JsonProperty("id")]
        public string Id { get; set; } = string.Empty;

        [JsonProperty("name")]
        public string? Name { get; set; }

        [JsonProperty("isComplete")]
        public bool IsComplete { get; set; }
    }
}

JsonProperty属性を使うと、JSONオブジェクト変換時の名称を指定することができます。

※2022年11月時点では、Cosmos DBのSDKがNewtonsoft.Jsonに依存しているため、System.Text.Json名前空間の属性を使って名称を変換しようとするとエラーになります。

Azure Cosmos DBを操作するサービスクラスの作成

Azure Cosmos DBに対するCRUD操作のロジックをまとめたサービスクラスを作成します。

具体的なロジックを定義する「CosmosDbService」と、それらをカプセル化したインターフェース「ICosmosDbService」を作成していきます。

まずプロジェクトの直下に「Services」というフォルダを作成し、その中に「ICosmosDbService」を追加してください。

using CosmosTodoApi.Models;

namespace CosmosTodoApi.Services
{
    public interface ICosmosDbService
    {
        Task<IEnumerable<TodoItem>> GetItemsAsync(string query);
        Task<TodoItem?> GetItemAsync(string id);
        Task AddItemAsync(TodoItem item);
        Task UpdateItemAsync(string id, TodoItem item);
        Task DeleteItemAsync(string id);
    }
}

同様に「CosmosDbService」という実装クラスを追加します。各処理の中身がわかるように簡単にコメントを付与しています。

using CosmosTodoApi.Models;
using Microsoft.Azure.Cosmos;

namespace CosmosTodoApi.Services
{
    public class CosmosDbService : ICosmosDbService
    {
        private readonly Container _container;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="cosmosClient">Cosmosクライアント</param>
        /// <param name="databaseName">データベース名</param>
        /// <param name="containerName">コンテナ名</param>
        public CosmosDbService(CosmosClient cosmosClient, string databaseName, string containerName)
        {
            _container = cosmosClient.GetContainer(databaseName, containerName);
        }

        /// <summary>
        /// クエリに一致するTodoアイテムを取得する
        /// </summary>
        /// <param name="queryString">SQLクエリ</param>
        /// <returns></returns>
        public async Task<IEnumerable<TodoItem>> GetItemsAsync(string queryString)
        {
            var query = _container.GetItemQueryIterator<TodoItem>(new QueryDefinition(queryString));

            var results = new List<TodoItem>();
            while (query.HasMoreResults)
            {
                var response = await query.ReadNextAsync();
                results.AddRange(response.ToList());
            }

            return results;
        }

        /// <summary>
        /// Todoアイテムを1件取得する
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns></returns>
        public async Task<TodoItem?> GetItemAsync(string id)
        {
            try
            {
                ItemResponse<TodoItem> response = await _container.ReadItemAsync<TodoItem>(id, new PartitionKey(id));
                return response.Resource;
            }
            // 404 Not Foundの場合はnullを返す
            catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                return null;
            }
        }

        /// <summary>
        /// Todoアイテムを登録する
        /// </summary>
        /// <param name="item">Todoアイテム</param>
        /// <returns></returns>
        public async Task AddItemAsync(TodoItem item)
        {
            await _container.CreateItemAsync<TodoItem>(item, new PartitionKey(item.Id));
        }

        /// <summary>
        /// Todoアイテムを更新する
        /// </summary>
        /// <param name="id">Id</param>
        /// <param name="item">Todoアイテム</param>
        /// <returns></returns>
        public async Task UpdateItemAsync(string id, TodoItem item)
        {
           await _container.UpsertItemAsync<TodoItem>(item, new PartitionKey(id));
        }

        /// <summary>
        /// Todoアイテムを削除する
        /// </summary>
        /// <param name="id">Id</param>
        /// <returns></returns>
        public async Task DeleteItemAsync(string id)
        {
            await _container.DeleteItemAsync<TodoItem>(id, new PartitionKey(id));
        }
    }
}

設定ファイルの変更

次にProgram.csを変更します。
Cosmos DBに接続するクライアントの初期設定と、クライアントのインスタンスをシングルトンにする(アプリ起動時に一度だけインスタンスを生成する)設定を記載します。

using CosmosTodoApi.Services;
using Microsoft.Azure.Cosmos;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

// Cosmosクライアントの初期化処理
static async Task<CosmosDbService> InitializeCosmosClientInstanceAsync(IConfigurationSection configurationSection)
{
    // appsettings.jsonからCosmosDBの設定値を取得
    var databaseName = configurationSection["DatabaseName"];
    var containerName = configurationSection["ContainerName"];
    var account = configurationSection["Account"];
    var key = configurationSection["Key"];

    // CosmosClientとCosmosDbServiceのインスタンスを生成
    var client = new CosmosClient(account, key);
    var cosmosDbService = new CosmosDbService(client, databaseName, containerName);

    // データベースが存在しない場合は新たに作成する
    var database = await client.CreateDatabaseIfNotExistsAsync(databaseName);

    // コンテナが存在しない場合は新たに作成する
    await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id");

    return cosmosDbService;
}

// Cosmosクライアントのシングルトンインスタンスを生成
builder.Services.AddSingleton<ICosmosDbService>(
    InitializeCosmosClientInstanceAsync(builder.Configuration.GetSection("CosmosDb")).GetAwaiter().GetResult());

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

appsettings.jsonにCosmos DBに関する情報を追加します。
Azureポータルで確認したURIとプライマリキーをコピペしてください。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "CosmosDb": {
    "Account": "<URI>",
    "Key": "<プライマリキー>",
    "DatabaseName": "Todo",
    "ContainerName": "TodoItem"
  }
}

デバッグ実行時の設定も変更します。

Properties/launchSettings.json内のlaunchUrlを以下のように変更してください。

...
  "profiles": {
    "CosmosTodoApi": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "api/todoitems",
      "applicationUrl": "https://localhost:<ポート番号>;http://localhost:<ポート番号>",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
...

APIコントローラーの作成

「Controllers」フォルダ内に「TodoItemsController」という名前の空のAPIコントローラーを追加し、以下のコードを記述します。

using CosmosTodoApi.Models;
using CosmosTodoApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace CosmosTodoApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
        private readonly ICosmosDbService _cosmosDbService;

        public TodoItemsController(ICosmosDbService cosmosDbService)
        {
            _cosmosDbService = cosmosDbService;
        }

        // GET: api/TodoItems
        [HttpGet]
        public async Task<ActionResult<IEnumerable<TodoItem>>> Get()
        {
            var result = await _cosmosDbService.GetItemsAsync("SELECT * FROM c");
            return result.ToList();
        }

        // GET: api/TodoItems/5
        [HttpGet("{id}")]
        public async Task<ActionResult<TodoItem>> GetTodoItem(string id)
        {
            var todoItem = await _cosmosDbService.GetItemAsync(id);

            if (todoItem == null)
            {
                return NotFound();
            }

            return todoItem;
        }

        // PUT: api/TodoItems/5
        [HttpPut]
        public async Task<IActionResult> Put(string id, TodoItem item)
        {
            if (id != item.Id)
            {
                return BadRequest();
            }

            await _cosmosDbService.UpdateItemAsync(id, item);
            return NoContent();
        }

        // POST: api/TodoItems
        [HttpPost]
        public async Task<ActionResult<TodoItem>> Post(TodoItem item)
        {
            item.Id = Guid.NewGuid().ToString();
            await _cosmosDbService.AddItemAsync(item);
            return CreatedAtAction("Get", new { id = item.Id }, item);
        }

        // DELETE: api/TodoItems/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> Delete(string id)
        {
            var todoItem = await _cosmosDbService.GetItemAsync(id);
            if (todoItem == null)
            {
                return NotFound();
            }

            await _cosmosDbService.DeleteItemAsync(id);
            return NoContent();
        }
    }
}

以上でAPIの作成は完了です。

動作確認

それでは正しくAPIが動くかどうかを確認してみましょう。
今回はPostmanを使ってAPIにリクエストしてみます。

※Postmanは下記ページからダウンロードできます。

Download Postman | Get Started for Free
Try Postman for free! Join 25 million developers who rely on Postman, the collaboration platform for API development. Cr...

データの登録

まずは新たなTodoアイテムを登録してみたいと思います。アプリをF5でデバッグ実行しておいてください。

URLは「https://localhost:<ポート番号>/api/todoitems」にし、bodyに下記のJSONを設定してPOSTリクエストを送信してみましょう。
※<ポート番号>には、デバッグ実行時にブラウザのアドレスバーに表示されているポート番号を設定してください。

{
    "name": "買い物をする",
    "isComplete": false
}

※このような画面が表示された場合は「Disable SSL Vertfication」をクリックしてください。

このようなレスポンスが返ってくれば成功です。

Cosmos DB側も見てみましょう。
データエクスプローラーでデータを展開すると、POSTしたデータがJSON形式で保存されていることが確認できます。

データの取得

登録したデータが取得できることを確認するため、api/todoitemsにGETリクエストを送ってみます。

「https://localhost:<ポート番号>/api/todoitems」宛にGETリクエストを送信してみてください。

このようなレスポンスが返ってくれば成功です。

以上でAPIが正しく動作していることが確認できました。

興味のある方はPUTやDELETEのAPI実行も試してみてください。

参考書籍

著:増田 智明
¥3,366 (2024/04/19 09:27時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場

コメント

タイトルとURLをコピーしました