ASP.NET Core Web APIの公式チュートリアルの内容をより丁寧に解説してみました。
ToDoアイテムを管理する簡単なAPIを作成していきます。
本記事の対象
- ASP.NET Core Web APIの基本的な仕組みを理解したい
- C#、REST APIの基本的な知識がある
環境
- Windows 11
- Visual Studio 2022
- .NET 8
プロジェクトの作成と実行
Visual Studioを起動したら、新規プロジェクトの作成画面を開き、「ASP.NET Core Web API」を選択します。
プロジェクト名はチュートリアルと同じ「TodoApi」にしました。
ターゲットフレームワークには「.NET 8.0(長期的なサポート)」を選択します。その他の項目はデフォルトのままでOKです。
プロジェクトの作成が完了したら、「Ctrl+F5」でデバッグなしで実行してみましょう。
もし、次の画面が表示された場合は「はい」を選択して証明書をインストールしてください。
ブラウザが起動し、以下のようなSwagger UIのページが表示されます。
Swagger UIとは
SwaggerとはAPIの仕様を管理するフレームワークで、Swagger UIはそれを構成するツールの1つです。
Swagger UIを使うと、設定されたAPIのドキュメントをWebベースで見やすく表示してくれます。ページ上からリクエストを送信して結果を確認することもできます。
ASP.NET Coreでは「Swashbuckle」というパッケージをインストールすると使用できますが、.NET 5 以降では標準でインストールされています。
(プロジェクト作成時に「Open APIサポートを有効にする」にチェックを入れた場合)
表示されている「WeatherForecast」とは、プロジェクトに最初から用意されているサンプルAPIです。試しに挙動を確認してみましょう。
「GET /WeatherForecast」をクリックすると詳細が開くので、「Try it out」→「Execute」の順でクリックして、リクエストを投げてみます。
すると、以下のようなレスポンスが返ってきました。
WeatherForecastは日付ごとの天気予報を返すAPIなので、Response Bodyには日時や気温が表示されています。
以上でAPIの動作確認ができました。
次からToDoアプリの作成していきますが、その前に今後起動する際のURLをSwagger UIからAPIに変えておきましょう。
Properties/launchSettings.json
内のlaunchUrl
を以下のように変更すればOKです。
※launchSettings.json
とは、ローカルでのアプリケーション起動に関する設定内容が記述されたファイルです。
...
"profiles": {
"TodoApi": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "api/todoitems",
"applicationUrl": "https://localhost:<ポート番号>;http://localhost:<ポート番号>",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
...
これで今後はSwagger UIではなく、https://localhost:<ポート番号>/api/todoitems
が開くようになります。
モデルクラスとDBContextの追加
それでは、ToDo APIの中身を実装していきます。
「TodoApi」プロジェクトを右クリックし、「追加」→「新しいフォルダー」でModels
フォルダを作成してください。
さらに、「Models」フォルダを右クリックし、「追加」→「クラス」でTodoItem.cs
というクラスを作成します。
作成できたら、TodoItemクラスを以下の通り書き換えましょう。
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
Id
にはテーブルの主キーが格納されます。IsComplete
はタスクが完了したかどうかを表すフラグです。
次に、モデルクラスとDBを対応付けるためにDbContextクラスを作成しますが、その前にEntityFramework Coreのパッケージをインストールしておきましょう。
プロジェクト名を右クリック→「NuGet パッケージの管理」を選択してNuGetパッケージマネージャーを開き、「参照」タブから「Microsoft.EntityFrameworkCore.InMemory」と検索します。
表示されたパッケージを選択して、インストールをクリックしてください。
インストールが完了したら、Models
フォルダ内にTodoContext.cs
というクラスを追加してください。
using Microsoft.EntityFrameworkCore;
namespace TodoApi.Models;
public class TodoContext : DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; } = null!;
}
次に、作成したTodoContextをアプリに登録するために、Program.csを変更します。
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
AddDbContext
でTodoContext
クラスをアプリに登録しています。
UseInMemoryDatabase
は、TodoContext
クラスがメモリ内のDBを使用することを指示するもので、実際のDBを用意せずにCRUD処理を実装する際に使用します。
コントローラーのスキャフォールディング
スキャフォールディングを実行すると、各CRUDメソッドが実装されたコントローラーを自動で生成することができます。早速実行してみましょう。
Controllers
フォルダを右クリックして、「追加」→「新規スキャフォールディングアイテム」をクリックします。
「Entity Framework を使用したアクションがある API コントローラー」を選択してから、 「追加」 をクリック。
モデルクラスに先ほど作成したTodoItem
を、DbContextクラスにTodoContext
を選択して「追加」をクリックすると、スキャフォールディングが開始されます。
スキャフォールディングが完了すると、TodoItemsController.cs
が自動的に作成されます。
TodoItemsControllerの確認
作成されたコントローラーを抜粋して内容を確認してみます。
...
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
// TodoContextクラスをControllerに挿入
public TodoItemsController(TodoContext context)
{
_context = context;
}
...
ここで使用されている属性やクラスについて簡単に説明します。
[Route]
属性
この属性を付与することで「属性ルーティング」(Program.csではなくController側のRoute属性によりルートの指定を行う)が使用できます。[Route("api/[controller]")]
の場合は「/api/コントローラー名」というURLが生成されます。コントローラー名には○○Controllerの○○の部分が入ります。[ApiController]
属性
この属性を付与することで、コントローラーがWeb APIのリクエストに応答することを示します。これにより上述の「属性ルーティング」や、「自動的なHTTP応答」(モデル検証でエラーが発生したら自動で400エラーがレスポンスとして返される)などの様々な機能が有効化されます。
詳細は以下のドキュメントを参照してください。
ASP.NET Core を使って Web API を作成するControllerBase
の継承
ビューを使用するMVCアプリの場合はControllerクラスを継承しますが、ビューが存在しないWeb APIではControllerBaseを継承します。ControllerBaseクラスにはHTTPリクエストの処理に役立つメソッドなどが多く含まれています。DbContext
クラスの挿入
作成したTodoContextクラスは、DIを使用してControllerに挿入されています。これにより各メソッド内でDbContextクラスを使用することができます。
PostTodoItemメソッドの確認
次にPostTodoItemメソッドを見てみましょう。
...
// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
// POSTされたデータをContextクラスに追加する
_context.TodoItems.Add(todoItem);
// Contextクラスに追加されたデータをDBに登録する(INSERT文が実行される)
await _context.SaveChangesAsync();
// ステータスコード201(Created)を返し、GetTodoItemメソッドを呼び出す
return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
}
...
POSTメソッドでリクエストされた内容をDBに登録して、登録した内容をレスポンスとして返すメソッドです。このメソッドの動作を確認してみましょう。
APIの動作確認にはPostmanなどのツールを使ってもいいですが、ここでは「HttpRepl」という公式のコマンドラインツールを使用します。
HttpReplのインストール
「ツール」→「コマンドライン」→「開発者コマンドプロンプト」でコマンドプロンプトを開きます。
以下のコマンドを実行してください。
dotnet tool install -g Microsoft.dotnet-httprepl
次のように表示されればインストール成功です。
PostTodoItemメソッドの動作確認
まずF5でアプリを起動し、コマンドプロンプト上で以下のコマンドを入力してください。
<ポート番号>にはブラウザのアドレスバーに表示されているポート番号を入力します。
httprepl https://localhost:<ポート番号>/api/todoitems
post -h Content-Type=application/json -c "{"name":"walk dog","isComplete":true}"
このコマンドで、https://localhost:<ポート番号>/api/todoitems
宛に、 “{"name":"walk dog","isComplete":true}
” という内容のJSONデータを、POSTメソッドでリクエストすることができます。
実行すると次のように表示され、リクエストしたToDoアイテムが登録されたことがわかります。
GetTodoItemメソッドの確認
次に2つのGETメソッドについて確認してみます。
エンドポイントGET: api/TodoItems
は、リクエストパラメータの指定がない場合は全件を返し、GET: api/TodoItems/{id}
はIDの指定がある場合に一致するTodoアイテムを返します。
...
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
// DB内のToDoデータを全て取得して返す
return await _context.TodoItems.ToListAsync();
}
// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
// リクエストされたIDと一致するDB内のTodoアイテムを取得
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
// 404 Not Found
return NotFound();
}
// 200 OK
return todoItem;
}
...
GET: api/TodoItems/{id}
については先ほどのPostTodoItemメソッドで確認できたので、 GET: api/TodoItems
の動作について確認してみます。
APIに接続している状態で「get」コマンドを実行することで、GETリクエストを送付できます。
(もし先ほどのコネクションを切断してしまった場合は、connect https://localhost:<ポート番号>/api/todoitems
で再度APIに接続してください。)
実行すると、先ほどPOSTで登録したアイテムが表示されます。
PutTodoItemメソッドの確認
次はPutTodoItemメソッドです。
PostTodoItemメソッドと似ていますが、一般的にPOSTが新規登録に使われるのに対して、PUTは更新に使われます。また、成功時のレスポンスのステータスはPOSTが「200 OK」ですが、PUTは「204 No Content」となります。
...
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
// エンティティ(todoItem)の状態をUnchanged(未変更)からModified(変更済)に変更する
_context.Entry(todoItem).State = EntityState.Modified;
try
{
// 変更のあったプロパティに対してUPDATE文が実行される
await _context.SaveChangesAsync();
}
// 同時実行制御に関する例外(更新中に別のユーザーによって値が書き換えられた場合など)
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
...
EF Coreでデータを更新をする際には、エンティティの状態を変更してからSaveChangesメソッドを実行します。
EF Coreが自動で変更されたプロパティを検知して、変更対象のデータのみに対してUPDATE文が実行されます。
以下のコマンドを実行して、ID=1のアイテムの名前を”walk dog”から”feed fish”に更新します。
connect https://localhost:<ポート番号>/api/todoitems/1
put -h Content-Type=application/json -c "{"id":1,"name":"feed fish","isComplete":true}"
「204 No Content」と表示されれば成功です。
「get」コマンドを実行すると、nameが変更されていることが確認できます。
DeleteTodoItemメソッドの確認
最後にDeleteメソッドを確認します。
...
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
// Removeメソッドで該当のTodoアイテムを削除する
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
...
以下のコマンドを実行して、id=1のアイテムを削除してみましょう。
connect https://localhost:<ポート番号>/api/todoitems/1
delete
「No Content」と表示されれば成功です。
getコマンドを実行すると、何も表示されないことが確認できます。
おわりに
とてもシンプルではありましたが、CRUD機能を備えたAPIの作成と確認を行いました。
ASP.NET Core Web APIを使えばとても簡単にAPIアプリを作成できるので、ぜひ様々なAPIを作成してみてください。
最後に、さらに学びたい方に向けておすすめの書籍や記事を紹介します。
ASP.NET Core の基本的な仕組みを知りたい
Program.cs
に記載されている内容を中心に、ASP.NET Core の裏側の動きについて解説しています。