C# API入門完全ガイド|REST APIの作り方・呼び出し方をサンプルコードで解説
はじめに
C# APIを学ぶと、Webサービス同士の連携、スマートフォンアプリのバックエンド開発、業務システムのデータ連携、外部サービスとの通信など、幅広い開発ができるようになります。特にC#では、ASP.NET Coreを使うことでREST APIを効率よく作成でき、さらにHttpClientを使えば外部APIの呼び出しも簡単に実装できます。
この記事では、C# APIの基礎から、REST APIの作り方、外部APIの呼び出し方、データベース連携、認証、エラー対応、テスト、公開方法までを初心者向けにまとめて解説します。サンプルコードを使いながら進めるため、「C#でAPIを作ってみたい」「REST APIを呼び出すコードを書きたい」「ASP.NET Core Web APIの基本を理解したい」という方に向いています。
1. C# APIとは?初心者が最初に理解すべき基礎知識
1-1. APIとは何か:アプリケーション同士をつなぐ仕組み
APIとは、Application Programming Interfaceの略で、アプリケーション同士が機能やデータをやり取りするための窓口です。たとえば、天気アプリが気象情報を取得する、ECサイトが決済サービスと連携する、社内システムが顧客情報を取得する、といった場面でAPIが使われます。
C# APIという場合、主にC#でAPIを作る、またはC#からAPIを呼び出す開発を指します。C#は業務システム、Webアプリ、クラウドアプリ、デスクトップアプリなどで広く使われているため、API開発との相性が非常に高い言語です。
APIを理解するうえで重要なのは、「APIは機能そのものではなく、機能を利用するための入り口」という点です。利用者は内部処理を知らなくても、決められたURL、HTTPメソッド、パラメータを使えば機能を呼び出せます。
1-2. C#で扱うAPIの主な種類
C#で扱うAPIには、いくつかの種類があります。代表的なものは次のとおりです。
Web APIは、HTTP通信を使ってデータや機能を提供するAPIです。現在のC# API開発では、ASP.NET Coreを使ったWeb APIがよく使われます。
REST APIは、URLとHTTPメソッドを組み合わせてリソースを操作する設計スタイルのAPIです。たとえば、GET /api/productsで商品一覧を取得し、POST /api/productsで商品を登録します。
ライブラリAPIは、.NETのクラスライブラリや外部ライブラリが提供する機能をコードから呼び出すものです。たとえば、System.Text.Jsonを使ってJSONを変換する処理もAPI利用の一種です。
OS APIやクラウドAPIもあります。Windowsの機能を呼び出したり、Azure、AWS、Google Cloudなどのクラウドサービスと連携したりする場面で使われます。
1-3. Web APIとREST APIの違い
Web APIは、Web経由で利用できるAPI全般を指します。一方、REST APIはWeb APIの設計スタイルのひとつです。つまり、REST APIはWeb APIの一種と考えると理解しやすいです。
Web APIには、RESTのほかにもGraphQL、gRPC、SOAPなどがあります。その中でもREST APIは、HTTPメソッドとURLを使ったシンプルな設計で、Webサービスや業務システムのAPIとして広く使われています。
たとえば、以下のようなURL設計はREST APIらしい形式です。
httpGET /api/books
GET /api/books/1
POST /api/books
PUT /api/books/1
DELETE /api/books/1
REST APIでは、「本」「商品」「ユーザー」などのデータをリソースとして扱い、HTTPメソッドによって取得、作成、更新、削除を表現します。
1-4. C# API開発でよく使うASP.NET Coreとは
ASP.NET Coreは、C#でWebアプリケーションやWeb APIを開発するためのフレームワークです。Microsoftの公式ドキュメントでも、ASP.NET Coreは高速で安全なクロスプラットフォームのWebアプリやサービスを作成するための技術として説明されています。ASP.NET Coreでは、Controllerを使ったWeb APIとMinimal APIの両方を作成できます。
C#でREST APIを作る場合、初心者にはまずControllerベースのASP.NET Core Web APIがおすすめです。Controller、ルーティング、DTO、Service、Repositoryなど、実務で使われる構成を学びやすいからです。
ASP.NET Coreでは、HTTPリクエストを受け取り、Controllerで処理し、JSON形式のレスポンスを返すAPIを簡単に作成できます。また、Swagger、DI、ログ、設定管理、認証、Entity Framework Coreとの連携など、API開発に必要な機能もそろっています。
1-5. APIを「作る側」と「呼び出す側」の違い
C# APIを学ぶときは、「APIを作る側」と「APIを呼び出す側」を分けて考えることが重要です。
APIを作る側は、ASP.NET Coreなどを使って、外部からアクセスできるエンドポイントを用意します。たとえば、商品一覧を返すGET /api/productsや、商品を登録するPOST /api/productsを作ります。
APIを呼び出す側は、HttpClientなどを使って外部APIにHTTPリクエストを送信し、レスポンスを受け取ります。たとえば、決済API、地図API、翻訳API、社内の別システムのAPIなどをC#から呼び出します。
同じC# API開発でも、この2つでは必要な知識が少し異なります。APIを作る側ではASP.NET Core、Controller、ルーティング、ステータスコード、データベース連携が重要です。APIを呼び出す側ではHttpClient、JSON変換、非同期処理、エラー処理が重要になります。
2. C#でREST APIを学ぶ前に必要な前提知識
2-1. HTTPメソッドの基本:GET・POST・PUT・DELETE
REST APIでは、HTTPメソッドを使って操作の種類を表します。代表的なHTTPメソッドは、GET、POST、PUT、DELETEです。
GETはデータを取得するときに使います。たとえば、商品一覧を取得する場合はGET /api/products、特定の商品を取得する場合はGET /api/products/1のようにします。
POSTは新しいデータを作成するときに使います。商品を登録する場合は、リクエストボディにJSONを含めてPOST /api/productsを送信します。
PUTは既存データを更新するときに使います。たとえば、IDが1の商品を更新する場合はPUT /api/products/1を使います。
DELETEはデータを削除するときに使います。IDが1の商品を削除する場合はDELETE /api/products/1のようにします。
C# APIを設計するときは、処理内容に合ったHTTPメソッドを選ぶことが大切です。すべてをPOSTで処理することも技術的には可能ですが、REST APIとしては分かりにくくなります。
2-2. URL・エンドポイント・ルーティングの考え方
APIでアクセスするURLのことを、エンドポイントと呼びます。たとえば、商品一覧を取得するAPIのエンドポイントは次のようになります。
httpGET https://example.com/api/products
ASP.NET Coreでは、ControllerやActionにルーティングを設定して、どのURLにアクセスしたときにどの処理を実行するかを決めます。
C#[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetAll()
{
return Ok();
}
}
この例では、ProductsControllerの[controller]部分がproductsに対応し、GET /api/productsでGetAllメソッドが呼び出されます。
2-3. リクエストとレスポンスの仕組み
API通信では、クライアントがリクエストを送り、サーバーがレスポンスを返します。
リクエストには、URL、HTTPメソッド、ヘッダー、クエリパラメータ、リクエストボディなどが含まれます。たとえば、商品登録APIでは、リクエストボディに商品名や価格をJSON形式で送信します。
レスポンスには、ステータスコード、ヘッダー、レスポンスボディなどが含まれます。成功した場合は200 OKや201 Created、エラーの場合は400 Bad Requestや404 Not Foundなどが返ります。
C# APIを作るときは、「どのようなリクエストを受け取り、どのようなレスポンスを返すか」を明確に設計することが重要です。
2-4. JSONとは何か:C#オブジェクトとの変換
JSONは、APIでよく使われるデータ形式です。人間が読みやすく、JavaScript、C#、Python、Javaなど多くの言語で扱いやすい特徴があります。
たとえば、商品データはJSONでは次のように表現できます。
JSON{
"id": 1,
"name": "Laptop",
"price": 120000
}
C#では、このJSONをクラスとして扱えます。
C#public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
ASP.NET Core Web APIでは、リクエストボディのJSONをC#オブジェクトに変換したり、C#オブジェクトをJSONとしてレスポンスしたりする処理を自動で行えます。
2-5. ステータスコードの基本:200・201・400・401・404・500
APIでは、処理結果をHTTPステータスコードで表します。C# API開発でよく使うステータスコードは次のとおりです。
200 OKは、処理が成功したことを表します。GETやPUTの成功時によく使います。
201 Createdは、新しいリソースの作成に成功したことを表します。POSTでデータを登録したときに使います。
400 Bad Requestは、リクエスト内容が不正であることを表します。必須項目が不足している、形式が間違っている、といった場合に使います。
401 Unauthorizedは、認証が必要、または認証に失敗したことを表します。
404 Not Foundは、指定されたリソースが存在しないことを表します。存在しないIDを指定したときなどに使います。
500 Internal Server Errorは、サーバー内部で予期しないエラーが発生したことを表します。
適切なステータスコードを返すことで、API利用者が結果を正しく判断できるようになります。
2-6. DTO・Model・Entityの違い
C# API開発では、DTO、Model、Entityという言葉がよく出てきます。
DTOはData Transfer Objectの略で、APIの入出力に使うデータ用クラスです。リクエストやレスポンスに必要な項目だけを定義します。
Modelは文脈によって意味が変わりますが、画面や処理で扱うデータ構造全般を指すことが多いです。
Entityは、データベースのテーブルに対応するクラスです。Entity Framework Coreを使う場合、Entityクラスをもとにテーブルを作成したり、データを読み書きしたりします。
実務では、EntityをそのままAPIレスポンスとして返すのではなく、DTOに変換して返す設計がよく使われます。これにより、データベース構造を外部に直接見せず、API仕様を安定させやすくなります。
3. C#でREST APIを作る準備
3-1. 必要な開発環境
C#でREST APIを作るには、主に次の環境を用意します。
まず、.NET SDKが必要です。.NET SDKには、C#のコンパイラ、実行環境、プロジェクト作成コマンドなどが含まれています。
次に、開発エディタまたはIDEを用意します。WindowsであればVisual Studio、Windows、macOS、Linuxで使うならVisual Studio Codeも選択肢になります。
APIの動作確認には、Swagger、Postman、curlなどを使います。ASP.NET Core Web APIプロジェクトではSwaggerを組み込みやすいため、初心者でもブラウザからAPIを試しやすいです。
データベースを使う場合は、SQL Server、SQLite、PostgreSQLなどを用意します。学習段階では、インメモリDBやSQLiteから始めると扱いやすいです。
3-2. Visual Studioと.NET SDKのインストール
Visual Studioを使う場合は、「ASP.NET と Web 開発」ワークロードを含めてインストールします。これにより、ASP.NET Core Web APIプロジェクトを作成するためのテンプレートや必要なツールが利用できます。
Visual Studio Codeを使う場合は、.NET SDKをインストールしたうえで、C# Dev Kitなどの拡張機能を導入すると開発しやすくなります。
インストール後は、ターミナルで次のコマンドを実行して、.NET SDKが使えるか確認します。
Bashdotnet --version
バージョン番号が表示されれば、.NET SDKの準備は完了です。
3-3. ASP.NET Core Web APIプロジェクトの作成方法
コマンドラインでASP.NET Core Web APIプロジェクトを作成する場合は、次のコマンドを実行します。
Bashdotnet new webapi -n SampleApi
cd SampleApi
dotnet run
実行後、ブラウザでSwaggerのURLにアクセスすると、作成されたAPIを確認できます。
Visual Studioを使う場合は、新しいプロジェクトの作成から「ASP.NET Core Web API」を選択します。プロジェクト名を入力し、フレームワークを選択して作成すれば、API開発の基本構成が用意されます。
ASP.NET Coreでは、ControllerベースのWeb APIとMinimal APIのどちらも作成できます。公式ドキュメントでも、ASP.NET CoreはControllerまたはMinimal APIを使ったWeb API作成をサポートすると説明されています。
3-4. プロジェクト構成の見方
ASP.NET Core Web APIプロジェクトを作成すると、主に次のようなファイルやフォルダが含まれます。
Program.csは、アプリケーションの起動設定を行うファイルです。DI、ミドルウェア、ルーティング、Swaggerなどの設定を書きます。
Controllersフォルダには、APIのエンドポイントを定義するControllerクラスを配置します。
appsettings.jsonには、接続文字列、ログ設定、外部APIのURLなどの設定値を書きます。
Properties/launchSettings.jsonには、ローカル実行時のURLや環境変数などが定義されます。
実務では、さらにModels、DTOs、Services、Repositories、Dataなどのフォルダを作り、役割ごとにコードを整理します。
3-5. Program.csの役割
Program.csは、ASP.NET Coreアプリケーションの起点です。APIを作るうえで非常に重要なファイルです。
基本的なProgram.csは次のようになります。
C#var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
builder.Services.AddControllers()ではControllerを使えるようにします。AddSwaggerGen()ではSwaggerを有効化します。app.MapControllers()ではControllerに定義したルーティングをアプリケーションに登録します。
API開発が進むと、ここにDbContext、Service、認証、CORS、ログ、HttpClientなどの設定を追加していきます。
3-6. SwaggerでAPIを確認する方法
Swaggerは、APIのエンドポイント、リクエスト形式、レスポンス形式をブラウザで確認できる便利なツールです。ASP.NET Core Web APIでは、Swaggerを使ってAPIを手動テストできます。
プロジェクトを実行し、Swagger UIにアクセスすると、登録されているAPI一覧が表示されます。各APIを開き、「Try it out」を押すと、ブラウザ上からGET、POST、PUT、DELETEなどのリクエストを送信できます。
Swaggerは開発中の確認に非常に便利ですが、本番環境で公開する場合は注意が必要です。内部APIや管理用APIの仕様が外部に見えてしまう可能性があるため、本番環境では公開範囲を制限する、認証をかける、無効化するなどの対応を検討します。
4. C#で簡単なREST APIを作成する手順
4-1. 今回作成するサンプルAPIの仕様
ここでは、商品データを扱うシンプルなC# REST APIを作成します。データベースは使わず、メモリ上のリストで管理します。
作成するAPIは次のとおりです。
httpGET /api/products 商品一覧を取得
GET /api/products/{id} 商品を1件取得
POST /api/products 商品を登録
PUT /api/products/{id} 商品を更新
DELETE /api/products/{id} 商品を削除
まずはデータベースを使わない形でCRUDの流れを理解し、その後にEntity Framework Coreを使ったデータベース連携へ進むと理解しやすくなります。
4-2. Controllerを作成する
ControllersフォルダにProductsController.csを作成します。
C#using Microsoft.AspNetCore.Mvc;
namespace SampleApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static readonly List<Product> Products =
[
new Product { Id = 1, Name = "Keyboard", Price = 5000 },
new Product { Id = 2, Name = "Mouse", Price = 3000 }
];
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
}
[ApiController]は、Web API用Controllerであることを示します。[Route("api/[controller]")]により、ProductsControllerは/api/productsというURLでアクセスできるようになります。
4-3. GET APIでデータを取得する
商品一覧を取得するGET APIを追加します。
C#[HttpGet]
public IActionResult GetAll()
{
return Ok(Products);
}
特定の商品をIDで取得するAPIも追加します。
C#[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
return Ok(product);
}
Ok()は200 OKを返します。商品が存在しない場合はNotFound()で404 Not Foundを返します。
4-4. POST APIでデータを登録する
商品を登録するPOST APIを追加します。
C#[HttpPost]
public IActionResult Create(Product product)
{
product.Id = Products.Max(p => p.Id) + 1;
Products.Add(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
CreatedAtAction()を使うと、201 Createdを返しつつ、作成したリソースを取得するための情報もレスポンスに含められます。
リクエスト例は次のとおりです。
JSON{
"name": "Monitor",
"price": 25000
}
4-5. PUT APIでデータを更新する
既存の商品を更新するPUT APIを追加します。
C#[HttpPut("{id}")]
public IActionResult Update(int id, Product updatedProduct)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
product.Name = updatedProduct.Name;
product.Price = updatedProduct.Price;
return NoContent();
}
更新成功時は、レスポンスボディが不要であればNoContent()を使って204 No Contentを返すことができます。
4-6. DELETE APIでデータを削除する
商品を削除するDELETE APIを追加します。
C#[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
Products.Remove(product);
return NoContent();
}
存在しないIDが指定された場合は404 Not Found、削除に成功した場合は204 No Contentを返します。
4-7. IActionResultと戻り値の使い分け
ASP.NET CoreのControllerでは、戻り値としてIActionResult、ActionResult<T>、具体的な型などを使えます。公式ドキュメントでも、ControllerのAction戻り値には具体的な型、IActionResult、ActionResult<T>、HttpResultsなどの選択肢があると説明されています。
初心者におすすめなのは、まずIActionResultを使う方法です。Ok()、NotFound()、BadRequest()、CreatedAtAction()などを柔軟に返せるため、APIの結果に応じたレスポンスを作りやすいからです。
一方、レスポンスの型を明確にしたい場合はActionResult<Product>のように書くと、Swagger上でもレスポンス型が分かりやすくなります。
C#[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
return product;
}
4-8. 動作確認用のサンプルコード
完成したControllerの例は次のとおりです。
C#using Microsoft.AspNetCore.Mvc;
namespace SampleApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private static readonly List<Product> Products =
[
new Product { Id = 1, Name = "Keyboard", Price = 5000 },
new Product { Id = 2, Name = "Mouse", Price = 3000 }
];
[HttpGet]
public IActionResult GetAll()
{
return Ok(Products);
}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
return Ok(product);
}
[HttpPost]
public IActionResult Create(Product product)
{
product.Id = Products.Max(p => p.Id) + 1;
Products.Add(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public IActionResult Update(int id, Product updatedProduct)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
product.Name = updatedProduct.Name;
product.Price = updatedProduct.Price;
return NoContent();
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var product = Products.FirstOrDefault(p => p.Id == id);
if (product is null)
{
return NotFound();
}
Products.Remove(product);
return NoContent();
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
}
このサンプルだけでも、C# APIの基本であるGET、POST、PUT、DELETEの流れを確認できます。
5. C# APIでデータベースを扱う方法
5-1. Entity Framework Coreとは
Entity Framework Core、通称EF Coreは、C#のオブジェクトを使ってデータベースを操作するためのO/RMです。Microsoftの公式ドキュメントでは、EF Coreは軽量で拡張可能なオープンソース、クロスプラットフォームのデータアクセス技術として説明されています。また、.NET開発者が.NETオブジェクトを使ってデータベースを扱えるようにし、多くのデータアクセスコードを削減できるとされています。
通常、データベースを操作するにはSQLを書きます。しかしEF Coreを使うと、C#のクラスやLINQを使ってデータの取得、登録、更新、削除を行えます。
C# APIでは、EF Coreを使ってデータベースと連携する構成がよく使われます。
5-2. DbContextを作成する
EF Coreでは、DbContextがデータベースとの接続やEntityの管理を担当します。
まず、必要なパッケージを追加します。SQLiteを使う例です。
Bashdotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
次に、DataフォルダにAppDbContext.csを作成します。
C#using Microsoft.EntityFrameworkCore;
using SampleApi.Entities;
namespace SampleApi.Data;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Product> Products => Set<Product>();
}
DbSet<Product>は、データベース上のProductsテーブルに対応します。
5-3. Entityクラスを定義する
EntitiesフォルダにProduct.csを作成します。
C#namespace SampleApi.Entities;
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
このEntityクラスをもとに、EF Coreはテーブル構造を判断します。Idは主キーとして扱われます。
次に、Program.csでDbContextを登録します。
C#using Microsoft.EntityFrameworkCore;
using SampleApi.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
appsettings.jsonには接続文字列を追加します。
JSON{
"ConnectionStrings": {
"DefaultConnection": "Data Source=sample.db"
}
}
5-4. マイグレーションを実行する
マイグレーションは、C#のEntity定義をもとにデータベーススキーマを作成・更新する仕組みです。公式ドキュメントでも、EF Coreのマイグレーションは、アプリケーションのデータモデルとデータベーススキーマを同期させるために、スキーマを段階的に更新する方法として説明されています。
マイグレーションを作成してデータベースに反映するには、次のコマンドを実行します。
Bashdotnet ef migrations add InitialCreate
dotnet ef database update
InitialCreateはマイグレーション名です。実行後、SQLiteの場合はsample.dbというデータベースファイルが作成されます。
5-5. データベースを使ったCRUD APIの実装
EF Coreを使ったControllerの例は次のとおりです。
C#using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using SampleApi.Data;
using SampleApi.Entities;
namespace SampleApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly AppDbContext _context;
public ProductsController(AppDbContext context)
{
_context = context;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var products = await _context.Products.ToListAsync();
return Ok(products);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var product = await _context.Products.FindAsync(id);
if (product is null)
{
return NotFound();
}
return Ok(product);
}
[HttpPost]
public async Task<IActionResult> Create(Product product)
{
_context.Products.Add(product);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, Product updatedProduct)
{
var product = await _context.Products.FindAsync(id);
if (product is null)
{
return NotFound();
}
product.Name = updatedProduct.Name;
product.Price = updatedProduct.Price;
await _context.SaveChangesAsync();
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
var product = await _context.Products.FindAsync(id);
if (product is null)
{
return NotFound();
}
_context.Products.Remove(product);
await _context.SaveChangesAsync();
return NoContent();
}
}
ToListAsync()やFindAsync()のような非同期メソッドを使うことで、データベースアクセス中にスレッドを効率よく使えます。
5-6. インメモリDBと実データベースの違い
インメモリDBは、アプリケーションの実行中だけメモリ上にデータを保存します。アプリを停止するとデータは消えます。学習、テスト、簡単なサンプルには便利ですが、本番用途には向きません。
実データベースは、SQL Server、PostgreSQL、MySQL、SQLiteなどにデータを永続化します。アプリを停止してもデータが残り、複数ユーザーからのアクセスやバックアップ、権限管理などにも対応できます。
初心者がC# APIを学ぶ場合は、まずインメモリやSQLiteでCRUDを理解し、その後SQL ServerやPostgreSQLなどの実データベースに進むとよいでしょう。
5-7. 実務で使いやすいRepositoryパターンの考え方
Repositoryパターンは、データアクセス処理をControllerから分離する設計方法です。Controllerに直接DbContextの処理を書きすぎると、コードが肥大化し、テストや修正が難しくなります。
Repositoryを使うと、Controllerは「商品を取得する」「商品を登録する」といった目的だけを呼び出し、具体的なデータベース処理はRepositoryに任せられます。
C#public interface IProductRepository
{
Task<List<Product>> GetAllAsync();
Task<Product?> GetByIdAsync(int id);
Task AddAsync(Product product);
Task SaveChangesAsync();
}
Service層と組み合わせることで、Controller、Service、Repositoryの責務を分けやすくなります。小規模なAPIでは必須ではありませんが、実務のC# API開発では保守性を高めるために検討する価値があります。
6. C#で外部REST APIを呼び出す方法
6-1. HttpClientとは
HttpClientは、C#からHTTPリクエストを送信し、HTTPレスポンスを受け取るためのクラスです。外部REST APIを呼び出すときによく使います。Microsoftの公式ドキュメントでも、HttpClientはURIで識別されるWebリソースにHTTP要求を行い、HTTP応答を処理するために使われる型として説明されています。
たとえば、外部の商品API、天気API、認証API、決済APIなどをC#から呼び出す場合にHttpClientを使います。
簡単なGETリクエストは次のように書けます。
C#using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/products");
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);
ただし、実務ではHttpClientを毎回newするのではなく、IHttpClientFactoryを使う方法が推奨されます。
6-2. GETリクエストで外部APIのデータを取得する
外部APIからデータを取得する基本例です。
C#using System.Net.Http.Json;
using var client = new HttpClient();
var products = await client.GetFromJsonAsync<List<ProductDto>>(
"https://api.example.com/products");
foreach (var product in products ?? [])
{
Console.WriteLine($"{product.Id}: {product.Name}");
}
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
}
GetFromJsonAsync<T>()を使うと、GETリクエストを送信し、レスポンスJSONをC#オブジェクトに変換できます。
6-3. POSTリクエストでJSONデータを送信する
POSTでJSONを送信する例です。
C#using System.Net.Http.Json;
using var client = new HttpClient();
var request = new CreateProductRequest
{
Name = "Tablet",
Price = 80000
};
var response = await client.PostAsJsonAsync(
"https://api.example.com/products",
request);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("登録に成功しました");
}
else
{
Console.WriteLine($"エラー: {response.StatusCode}");
}
public class CreateProductRequest
{
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
PostAsJsonAsync()を使うと、C#オブジェクトをJSONに変換してPOSTできます。
6-4. レスポンスJSONをC#クラスに変換する
レスポンスJSONをC#クラスに変換するには、System.Text.JsonやSystem.Net.Http.Jsonを使います。
C#using System.Text.Json;
var json = """
{
"id": 1,
"name": "Keyboard",
"price": 5000
}
""";
var product = JsonSerializer.Deserialize<ProductDto>(json);
Console.WriteLine(product?.Name);
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
JSONのプロパティ名とC#のプロパティ名が異なる場合は、JsonPropertyName属性を使います。
C#using System.Text.Json.Serialization;
public class ProductDto
{
[JsonPropertyName("product_id")]
public int Id { get; set; }
[JsonPropertyName("product_name")]
public string Name { get; set; } = "";
}
6-5. async/awaitを使った非同期処理
API呼び出しやデータベースアクセスは、処理に時間がかかる可能性があります。そのため、C# API開発ではasyncとawaitを使った非同期処理がよく使われます。
C#public async Task<List<ProductDto>> GetProductsAsync()
{
using var client = new HttpClient();
var products = await client.GetFromJsonAsync<List<ProductDto>>(
"https://api.example.com/products");
return products ?? [];
}
awaitを使うことで、APIレスポンスを待っている間にスレッドをブロックしにくくなります。Web APIでは、多数のリクエストを効率よく処理するためにも非同期処理が重要です。
6-6. HttpClientを使うときの注意点
HttpClientは便利ですが、使い方には注意が必要です。特に、リクエストごとにnew HttpClient()を繰り返す設計は避けるべきです。接続管理やDNS更新などで問題が起きる可能性があります。
また、外部API呼び出しでは、タイムアウト、リトライ、認証ヘッダー、ステータスコードの判定、レスポンスJSONの形式変更などを考慮する必要があります。
最低限、次の点を意識しましょう。
C#var response = await client.GetAsync("https://api.example.com/products");
if (!response.IsSuccessStatusCode)
{
throw new Exception($"API呼び出しに失敗しました: {response.StatusCode}");
}
成功時だけでなく、失敗時にどう処理するかを設計することが大切です。
6-7. IHttpClientFactoryを使った実務向けの呼び出し方
実務のASP.NET Coreアプリでは、IHttpClientFactoryを使ってHttpClientを作成する方法がよく使われます。公式ドキュメントでは、IHttpClientFactoryはHttpClientインスタンスを構成・作成するために使え、名前付きクライアントの設定、DI、ログ、構成などと組み合わせられると説明されています。
まず、Program.csに登録します。
C#builder.Services.AddHttpClient("ProductApi", client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
client.Timeout = TimeSpan.FromSeconds(10);
});
Serviceクラスで使う例です。
C#using System.Net.Http.Json;
public class ProductApiClient
{
private readonly HttpClient _httpClient;
public ProductApiClient(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient("ProductApi");
}
public async Task<List<ProductDto>> GetProductsAsync()
{
var products = await _httpClient.GetFromJsonAsync<List<ProductDto>>("products");
return products ?? [];
}
}
DIに登録します。
C#builder.Services.AddScoped<ProductApiClient>();
IHttpClientFactoryを使うことで、HttpClientの設定を一元管理しやすくなり、保守性の高いC# API連携を実装できます。
7. C# API開発でよく使う実装パターン
7-1. 入力値バリデーションの実装
APIでは、外部から送信された値をそのまま信用してはいけません。必須項目、文字数、数値範囲、メールアドレス形式などを検証する必要があります。
ASP.NET Coreでは、DataAnnotationsを使って簡単にバリデーションできます。
C#using System.ComponentModel.DataAnnotations;
public class CreateProductRequest
{
[Required]
[StringLength(100)]
public string Name { get; set; } = "";
[Range(1, 1000000)]
public decimal Price { get; set; }
}
Controllerでは次のように受け取ります。
C#[HttpPost]
public IActionResult Create(CreateProductRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok();
}
[ApiController]を付けている場合、モデルバリデーションに失敗したリクエストは自動的に400 Bad Requestになるため、基本的な入力チェックを簡潔に実装できます。
7-2. エラーハンドリングの基本
C# APIでは、エラーが発生したときに適切なレスポンスを返すことが重要です。例外をそのまま外部に返すと、内部構造や機密情報が漏れる可能性があります。
基本方針は、想定内のエラーはControllerやServiceで明示的に処理し、想定外のエラーは共通エラーハンドリングで処理することです。
たとえば、指定された商品が存在しない場合は例外ではなく404 Not Foundを返します。
C#if (product is null)
{
return NotFound(new { message = "商品が見つかりません" });
}
一方、データベース接続エラーなどの予期しない例外は、共通処理で500 Internal Server Errorに変換します。
7-3. 例外発生時のレスポンス設計
例外発生時のレスポンスは、API利用者が原因を理解しやすい形式にします。ただし、スタックトレースや接続文字列などの内部情報は返してはいけません。
例として、次のような形式が考えられます。
JSON{
"message": "サーバー内部でエラーが発生しました",
"traceId": "00-abc123..."
}
開発環境では詳細なエラーを確認し、本番環境では利用者向けの安全なメッセージだけを返す設計にします。
共通エラーハンドリングは、ミドルウェアとして実装できます。
C#app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
await context.Response.WriteAsJsonAsync(new
{
message = "サーバー内部でエラーが発生しました"
});
});
});
7-4. DIによるServiceクラスの分離
DIとはDependency Injectionの略で、依存関係を外部から注入する仕組みです。ASP.NET CoreではDIが標準で用意されています。
Controllerにすべての処理を書くのではなく、業務ロジックをServiceクラスに分離すると、保守性が高くなります。
C#public interface IProductService
{
Task<List<ProductDto>> GetAllAsync();
}
C#public class ProductService : IProductService
{
public async Task<List<ProductDto>> GetAllAsync()
{
await Task.CompletedTask;
return
[
new ProductDto { Id = 1, Name = "Keyboard" }
];
}
}
Program.csでDI登録します。
C#builder.Services.AddScoped<IProductService, ProductService>();
Controllerではコンストラクタで受け取ります。
C#public class ProductsController : ControllerBase
{
private readonly IProductService _service;
public ProductsController(IProductService service)
{
_service = service;
}
}
この構成により、ControllerはHTTPの入出力、Serviceは業務処理、Repositoryはデータアクセスというように責務を分離できます。
7-5. ログ出力の実装
ログは、APIの動作確認、障害調査、監視に欠かせません。ASP.NET CoreではILogger<T>を使ってログを出力できます。
C#public class ProductsController : ControllerBase
{
private readonly ILogger<ProductsController> _logger;
public ProductsController(ILogger<ProductsController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult GetAll()
{
_logger.LogInformation("商品一覧APIが呼び出されました");
return Ok();
}
}
エラー時にはLogErrorを使います。
C#try
{
// 処理
}
catch (Exception ex)
{
_logger.LogError(ex, "商品登録中にエラーが発生しました");
throw;
}
ログには、リクエストID、ユーザーID、対象データのIDなど、調査に役立つ情報を含めると便利です。ただし、パスワード、トークン、個人情報などの機密情報をログに出力してはいけません。
7-6. appsettings.jsonで設定値を管理する
APIの設定値は、コードに直接書くのではなくappsettings.jsonで管理します。
JSON{
"ConnectionStrings": {
"DefaultConnection": "Data Source=sample.db"
},
"ExternalApis": {
"ProductApiBaseUrl": "https://api.example.com/"
}
}
C#コードから読み取る例です。
C#var baseUrl = builder.Configuration["ExternalApis:ProductApiBaseUrl"];
外部APIのURL、接続文字列、ログレベル、認証設定などは、設定ファイルで管理すると環境ごとの差し替えが簡単になります。
7-7. 環境ごとの設定切り替え
ASP.NET Coreでは、開発環境、本番環境、検証環境などで設定を切り替えられます。
代表的な設定ファイルは次のとおりです。
appsettings.json
appsettings.Development.json
appsettings.Production.json
開発環境ではSQLite、本番環境ではSQL Serverを使う、といった切り替えが可能です。
また、パスワードやAPIキーなどの機密情報は、ソースコードやGitに含めないようにします。開発環境ではユーザーシークレット、本番環境では環境変数やクラウドのシークレット管理サービスを使うと安全です。
8. C# REST APIの認証・認可の基本
8-1. APIに認証が必要な理由
APIは外部から呼び出される入口です。そのため、誰でも自由に使える状態にしておくと、不正アクセス、情報漏えい、データ改ざん、大量アクセスによる障害などのリスクがあります。
認証は「誰であるか」を確認する仕組みです。認可は「そのユーザーが何をできるか」を判断する仕組みです。
たとえば、ログイン済みユーザーだけが注文履歴を取得できるようにするのが認証です。管理者だけが商品を削除できるようにするのが認可です。
8-2. APIキー認証とは
APIキー認証は、事前に発行したキーをリクエストに含めてAPIを呼び出す方式です。シンプルで実装しやすいため、サーバー間連携や簡易的な認証で使われます。
例として、ヘッダーにAPIキーを含めます。
httpX-API-Key: abcdef123456
C# API側では、ミドルウェアやフィルターでAPIキーを検証します。
C#var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (apiKey != "expected-key")
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
ただし、APIキーが漏れると不正利用される可能性があるため、HTTPSの利用、キーのローテーション、利用範囲の制限が重要です。
8-3. Bearer Tokenとは
Bearer Tokenは、HTTPヘッダーのAuthorizationにトークンを指定する方式です。
httpAuthorization: Bearer eyJhbGciOi...
Bearerは「このトークンを持っている人にアクセスを許可する」という考え方です。JWT認証でも、このBearer Token形式がよく使われます。
C#で外部APIを呼び出す場合は、次のようにヘッダーを設定します。
C#client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
8-4. JWT認証の仕組み
JWTはJSON Web Tokenの略で、ユーザー情報や有効期限などを含んだトークンです。ログイン成功時にサーバーがJWTを発行し、クライアントは以後のAPIリクエストでJWTを送信します。
JWTには、ヘッダー、ペイロード、署名が含まれます。署名によって改ざんを検証できます。
C# APIでは、ASP.NET Coreの認証機能を使ってJWTを検証できます。
C#builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://auth.example.com";
options.Audience = "sample-api";
});
その後、ミドルウェアを有効化します。
C#app.UseAuthentication();
app.UseAuthorization();
UseAuthentication()は、ユーザーを識別する処理です。UseAuthorization()は、アクセス権限を確認する処理です。
8-5. Authorize属性の使い方
認証が必要なAPIには、[Authorize]属性を付けます。
C#[Authorize]
[HttpGet("me")]
public IActionResult GetMyProfile()
{
return Ok();
}
Controller全体に認証をかけることもできます。
C#[ApiController]
[Route("api/[controller]")]
[Authorize]
public class OrdersController : ControllerBase
{
}
一部のAPIだけ匿名アクセスを許可したい場合は、[AllowAnonymous]を使います。
C#[AllowAnonymous]
[HttpPost("login")]
public IActionResult Login()
{
return Ok();
}
管理者だけに許可する場合は、RoleやPolicyを使います。
C#[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
return NoContent();
}
8-6. 認証エラーと認可エラーの違い
認証エラーと認可エラーは似ていますが、意味が異なります。
認証エラーは、ユーザーを確認できない状態です。トークンがない、トークンが無効、有効期限切れなどの場合は401 Unauthorizedを返します。
認可エラーは、ユーザーは確認できているが、操作権限がない状態です。一般ユーザーが管理者APIを呼び出した場合などは403 Forbiddenを返します。
この違いを正しく使い分けることで、API利用者が原因を判断しやすくなります。
9. C# APIで発生しやすいエラーと解決方法
9-1. 404 Not Foundが返る原因
404 Not Foundは、指定されたURLやリソースが見つからないときに返ります。
C# APIでよくある原因は、ルーティングの指定ミスです。たとえば、Controllerに[Route("api/[controller]")]を付けている場合、ProductsControllerのURLは/api/productsになります。/api/productのように単数形でアクセスすると404になることがあります。
また、[HttpGet("{id}")]が必要なのに定義していない、Controller名やAction名を間違えている、app.MapControllers()を書いていない、という原因もあります。
データが存在しない場合にも404を返します。
C#var product = await _context.Products.FindAsync(id);
if (product is null)
{
return NotFound();
}
9-2. 400 Bad Requestが返る原因
400 Bad Requestは、リクエストの形式や内容が不正な場合に返ります。
よくある原因は、JSONの形式が間違っている、必須項目がない、型が一致しない、バリデーションに失敗している、などです。
たとえば、priceが数値であるべきところに文字列を送ると、モデルバインディングに失敗する可能性があります。
JSON{
"name": "Keyboard",
"price": "abc"
}
API利用者向けには、どの項目が不正なのか分かるレスポンスを返すと親切です。
9-3. 500 Internal Server Errorの原因
500 Internal Server Errorは、サーバー内部で予期しないエラーが発生したときに返ります。
C# APIでよくある原因は、NullReferenceException、データベース接続エラー、設定値の不足、外部APIの呼び出し失敗、例外処理の不足などです。
500エラーが発生した場合は、レスポンスだけで原因を特定するのは難しいため、ログを確認します。特に本番環境では、利用者には汎用的なエラーメッセージを返し、詳細はサーバーログに記録する設計が安全です。
9-4. JSONの変換エラーが起きる原因
JSON変換エラーは、リクエストJSONとC#クラスの構造が合っていない場合に起こります。
たとえば、C#側で数値を期待しているプロパティに文字列が送られる、日付形式が不正、JSONのカンマやダブルクォートが不足している、といったケースです。
また、プロパティ名が一致しない場合は、期待した値が入らないことがあります。その場合は、JSONのプロパティ名をC#側に合わせるか、JsonPropertyName属性を使います。
C#[JsonPropertyName("product_name")]
public string Name { get; set; } = "";
9-5. CORSエラーの原因と対策
CORSエラーは、ブラウザから別ドメインのAPIにアクセスしたときに発生することがあります。たとえば、フロントエンドがhttp://localhost:3000、APIがhttps://localhost:5001で動いている場合、ブラウザのセキュリティ制限によりブロックされることがあります。
ASP.NET Coreでは、CORSポリシーを設定します。
C#builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
ミドルウェアを有効化します。
C#app.UseCors("AllowFrontend");
本番環境では、AllowAnyOrigin()を安易に使わず、許可するオリジンを明確に指定することが重要です。
9-6. HttpClientで接続できないときの確認ポイント
HttpClientで外部APIに接続できない場合は、まずURLが正しいか確認します。httpsとhttpの違い、末尾スラッシュ、パス、クエリパラメータの指定ミスがよくあります。
次に、認証ヘッダーやAPIキーが正しいか確認します。外部APIでは、Bearer TokenやAPIキーがないと401 Unauthorizedが返ることがあります。
タイムアウト、SSL証明書、プロキシ、DNS、ネットワーク制限も原因になります。ステータスコードとレスポンス本文をログに出力すると、原因を特定しやすくなります。
C#var response = await client.GetAsync("products");
var body = await response.Content.ReadAsStringAsync();
_logger.LogInformation("Status: {StatusCode}, Body: {Body}", response.StatusCode, body);
9-7. SwaggerでAPIが表示されないときの対処法
SwaggerにAPIが表示されない場合は、まずProgram.csの設定を確認します。
C#builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
C#app.UseSwagger();
app.UseSwaggerUI();
Controllerを使う場合は、builder.Services.AddControllers()とapp.MapControllers()も必要です。
C#builder.Services.AddControllers();
app.MapControllers();
また、Controllerに[ApiController]や[Route]が正しく付いているか、Actionに[HttpGet]、[HttpPost]などが付いているかも確認します。
10. C# APIをテストする方法
10-1. Swaggerを使った手動テスト
Swaggerは、C# APIの手動テストに便利です。ブラウザからAPI一覧を確認し、パラメータやリクエストボディを入力して実行できます。
開発初期は、SwaggerでGET、POST、PUT、DELETEを試し、レスポンスのステータスコードやJSON形式を確認するとよいでしょう。
ただし、Swaggerだけでは複雑なシナリオテストや自動テストには不十分です。認証、複数APIの連続実行、異常系の網羅などには、Postmanや単体テストを組み合わせます。
10-2. Postmanを使ったAPIテスト
Postmanは、APIテスト用の代表的なツールです。URL、HTTPメソッド、ヘッダー、ボディを設定してAPIを呼び出せます。
Postmanでは、環境変数を使って開発環境と本番環境のURLを切り替えたり、認証トークンを保存したりできます。また、テストスクリプトを書いて、ステータスコードやレスポンス内容を自動で検証することもできます。
たとえば、商品登録APIでは、次のような観点で確認します。
POSTで201 Createdが返るか、必須項目がない場合に400 Bad Requestが返るか、登録後にGETで取得できるか、認証が必要なAPIでトークンなしの場合に401が返るか、といった点です。
10-3. curlコマンドでAPIを確認する
curlは、コマンドラインからAPIを呼び出すためのツールです。CI/CDや簡単な動作確認にも使いやすいです。
GETリクエストの例です。
Bashcurl https://localhost:5001/api/products
POSTリクエストの例です。
Bashcurl -X POST https://localhost:5001/api/products \
-H "Content-Type: application/json" \
-d "{\"name\":\"Keyboard\",\"price\":5000}"
Bearer Tokenを付ける場合は、次のようにします。
Bashcurl https://localhost:5001/api/orders \
-H "Authorization: Bearer your-token"
curlで確認できるようにしておくと、環境に依存しない形でAPIの動作を共有しやすくなります。
10-4. 単体テストの基本
単体テストは、ServiceやRepositoryなどの個別の処理が正しく動くかを確認するテストです。C#では、xUnit、NUnit、MSTestなどのテストフレームワークが使われます。
API開発では、Controllerだけでなく、業務ロジックをServiceに分離して単体テストを書くと保守性が高まります。
たとえば、「価格が0以下の商品は登録できない」「存在しない商品IDならnullを返す」「合計金額が正しく計算される」といったロジックをテストします。
10-5. xUnitを使ったテストコード例
xUnitを使った簡単なテスト例です。
C#public class ProductServiceTests
{
[Fact]
public void CalculateTaxIncludedPrice_ReturnsCorrectValue()
{
var service = new ProductService();
var result = service.CalculateTaxIncludedPrice(1000);
Assert.Equal(1100, result);
}
}
public class ProductService
{
public decimal CalculateTaxIncludedPrice(decimal price)
{
return price * 1.1m;
}
}
非同期メソッドのテストは次のように書けます。
C#[Fact]
public async Task GetProductsAsync_ReturnsProducts()
{
var service = new ProductService();
var products = await service.GetProductsAsync();
Assert.NotEmpty(products);
}
テストしやすいC# APIにするには、Controllerに処理を書きすぎず、ServiceやRepositoryに分けることが重要です。
10-6. APIテストで確認すべき項目
APIテストでは、正常系だけでなく異常系も確認します。
正常系では、期待したステータスコードが返るか、レスポンスJSONの形式が正しいか、登録や更新がデータベースに反映されるかを確認します。
異常系では、存在しないIDを指定した場合に404が返るか、不正な入力で400が返るか、認証なしで401が返るか、権限不足で403が返るかを確認します。
また、実務ではパフォーマンス、同時アクセス、ログ出力、セキュリティ、CORS、HTTPSなども確認対象になります。
11. C# APIを公開・運用する方法
11-1. ローカル環境と本番環境の違い
ローカル環境は、開発者のPC上でAPIを動かす環境です。デバッグしやすく、設定も簡易的です。
本番環境は、実際のユーザーやシステムが利用する環境です。安定性、セキュリティ、監視、バックアップ、スケーリングなどが重要になります。
ローカルではSwaggerを自由に使い、詳細なエラーを表示しても問題ないことがあります。しかし本番では、Swaggerの公開制限、詳細エラーの非表示、HTTPS、認証、ログ監視、環境変数による機密情報管理が必要です。
11-2. IISにデプロイする方法
Windows ServerでC# APIを公開する場合、IISにデプロイする方法があります。
基本的な流れは、サーバーに.NET Hosting Bundleをインストールし、APIを発行して、IISのサイトとして配置します。
Visual Studioから発行する場合は、「発行」機能を使ってフォルダに出力し、そのファイルをIISの公開フォルダに配置します。
コマンドで発行する場合は、次のようにします。
Bashdotnet publish -c Release -o ./publish
IISでは、アプリケーションプール、物理パス、バインディング、HTTPS証明書、環境変数などを設定します。
11-3. Azure App Serviceに公開する方法
Azure App Serviceを使うと、C# APIをクラウド上に比較的簡単に公開できます。
Visual StudioからAzure App Serviceへ直接発行することもできますし、GitHub ActionsやAzure DevOpsを使ってCI/CDを構築することもできます。
Azure App Serviceでは、アプリケーション設定として接続文字列や環境変数を管理できます。これにより、appsettings.jsonに機密情報を書かずに本番環境の設定を行えます。
また、スケールアウト、カスタムドメイン、HTTPS、ログ、監視などの機能も利用できます。
11-4. DockerでAPIを動かす方法
Dockerを使うと、C# APIの実行環境をコンテナとしてまとめられます。開発環境と本番環境の差を減らし、デプロイしやすくなるメリットがあります。
簡単なDockerfileの例です。
dockerfileFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "SampleApi.dll"]
ビルドと実行は次のように行います。
Bashdocker build -t sample-api .
docker run -p 8080:8080 sample-api
Docker Composeを使えば、APIとデータベースをまとめて起動できます。
11-5. HTTPS対応の基本
APIを公開する場合、HTTPS対応は必須です。HTTPのままだと、通信内容が盗聴・改ざんされるリスクがあります。特に、認証トークン、APIキー、個人情報、決済情報などを扱うAPIではHTTPSが重要です。
ASP.NET Coreでは、app.UseHttpsRedirection()を使うことでHTTPからHTTPSへのリダイレクトを設定できます。
C#app.UseHttpsRedirection();
本番環境では、IIS、Azure App Service、Nginx、ロードバランサーなどでTLS証明書を設定します。
11-6. API公開前に確認すべきセキュリティ項目
C# APIを公開する前には、最低限次の項目を確認します。
認証が必要なAPIに[Authorize]が設定されているか、管理者用APIに適切な認可があるか、APIキーや接続文字列がソースコードに書かれていないか、HTTPSが有効か、CORS設定が広すぎないか、詳細な例外情報を本番で返していないか、ログに機密情報を出力していないかを確認します。
また、不要なSwagger公開、デバッグ用エンドポイント、テストデータ、初期パスワードなどが残っていないかも確認します。
APIは外部との接点になるため、公開前のセキュリティ確認は非常に重要です。
12. C# API開発のベストプラクティス
12-1. Controllerに処理を書きすぎない
初心者がやりがちな失敗のひとつが、Controllerにすべての処理を書いてしまうことです。最初は問題なく見えても、機能が増えるとControllerが肥大化し、修正やテストが難しくなります。
Controllerは、HTTPリクエストを受け取り、Serviceを呼び出し、HTTPレスポンスを返す役割に集中させます。業務ロジックはService、データアクセスはRepositoryやDbContextに分離します。
この分離により、コードの見通しがよくなり、単体テストも書きやすくなります。
12-2. DTOを使って入出力を分離する
EntityをそのままAPIのリクエストやレスポンスに使うと、データベース構造が外部仕様に直結してしまいます。これは保守性やセキュリティの面で問題になることがあります。
たとえば、User EntityにPasswordHashが含まれている場合、それを誤ってAPIレスポンスに含めてしまうリスクがあります。
DTOを使えば、APIで受け取る項目、返す項目を明確に制御できます。
C#public class ProductResponse
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
EntityとDTOを分けることで、内部構造を守りつつ、API仕様を安定させられます。
12-3. 適切なHTTPステータスコードを返す
C# APIでは、処理結果に合ったHTTPステータスコードを返すことが重要です。
取得成功なら200 OK、作成成功なら201 Created、更新や削除でレスポンスボディが不要なら204 No Content、不正なリクエストなら400 Bad Request、認証エラーなら401 Unauthorized、権限不足なら403 Forbidden、存在しないリソースなら404 Not Foundを返します。
すべてのエラーを500にしたり、すべての成功を200にしたりすると、API利用者が正しく処理できません。ステータスコードを適切に使うことは、使いやすいAPI設計の基本です。
12-4. APIの命名ルールを統一する
APIのURLやJSONプロパティの命名ルールは統一しましょう。
REST APIでは、リソース名は名詞で表すのが一般的です。
httpGET /api/products
POST /api/products
GET /api/products/1
次のように動詞をURLに含めすぎると、REST APIとしては分かりにくくなります。
httpGET /api/getProducts
POST /api/createProduct
操作はHTTPメソッドで表し、URLはリソースを表すようにすると、API全体に一貫性が出ます。
12-5. OpenAPI仕様を整備する
OpenAPI仕様は、APIのエンドポイント、パラメータ、リクエスト、レスポンスなどを記述する標準的な仕様です。Swagger UIはOpenAPI仕様をもとにAPIドキュメントを表示します。
API仕様が整備されていると、フロントエンド開発者、外部連携先、テスト担当者がAPIを理解しやすくなります。
C# APIでは、レスポンス型やステータスコードを明示すると、Swagger上の表示も分かりやすくなります。
C#[ProducesResponseType(typeof(ProductResponse), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
return Ok();
}
12-6. バージョニングを考慮する
APIは一度公開すると、利用者が存在するため簡単には変更できません。レスポンス形式を変えたり、項目を削除したりすると、既存のクライアントが動かなくなる可能性があります。
そのため、APIのバージョニングを考慮します。
URLにバージョンを含める例です。
http/api/v1/products
/api/v2/products
ヘッダーでバージョンを指定する方法もありますが、初心者にはURLでバージョンを分ける方法が分かりやすいです。
バージョニングを意識しておくと、将来の仕様変更に対応しやすくなります。
12-7. 保守しやすいフォルダ構成にする
小さなサンプルではファイル数が少ないため、構成をあまり気にしなくても動きます。しかし実務のC# APIでは、フォルダ構成が保守性に大きく影響します。
一例として、次のような構成があります。
Controllers
DTOs
Entities
Services
Repositories
Data
Options
Middlewares
ControllerはHTTPの入口、DTOsはAPI入出力、Entitiesはデータベース対応クラス、Servicesは業務ロジック、Repositoriesはデータアクセス、DataはDbContext、Optionsは設定値、Middlewaresは共通処理を置きます。
プロジェクトの規模に応じて構成を調整し、役割が分かる配置にすることが大切です。
13. C# API学習でよくある質問
13-1. C#だけでAPIは作れる?
C#だけでもAPIのロジックは書けますが、Web APIとして公開するにはASP.NET Coreのようなフレームワークを使うのが一般的です。
C#は言語であり、ASP.NET CoreはWeb APIを作るためのフレームワークです。実際のC# API開発では、C#とASP.NET Coreを組み合わせてREST APIを作ります。
13-2. ASP.NET Coreと.NET Frameworkの違いは?
ASP.NET Coreは、現在の.NET環境でWebアプリやWeb APIを作るためのモダンなフレームワークです。クロスプラットフォームで、Windows以外の環境でも動作します。
.NET Frameworkは、主にWindows向けの従来のフレームワークです。既存の業務システムでは今も使われていますが、新規でC# APIを学ぶならASP.NET Coreを選ぶのが基本です。
13-3. Minimal APIとController APIはどちらを使うべき?
Minimal APIは、少ないコードでAPIを作れる方法です。小規模なAPI、マイクロサービス、簡単なエンドポイントには向いています。
Controller APIは、Controllerクラスを使ってAPIを整理する方法です。属性ルーティング、フィルター、バリデーション、認証、Swagger連携などを体系的に学びやすく、中規模以上の開発にも向いています。
初心者がC# APIを基礎から学ぶなら、まずController APIを学ぶのがおすすめです。その後、Minimal APIを学ぶと違いが理解しやすくなります。
13-4. Web APIとMVCの違いは?
Web APIは、主にJSONなどのデータを返すための仕組みです。フロントエンドアプリ、スマートフォンアプリ、外部システムなどから呼び出されます。
MVCは、HTML画面を返すWebアプリケーションを作るための構成です。Controller、Model、Viewを使って画面を生成します。
ASP.NET Coreでは、Web APIもMVCもControllerを使うため似ていますが、Web APIはデータを返し、MVCは画面を返すと考えると分かりやすいです。
13-5. RESTSharpとHttpClientはどちらを使うべき?
C#で外部APIを呼び出す場合、標準機能としてHttpClientが使えます。追加ライブラリなしで利用でき、ASP.NET CoreではIHttpClientFactoryと組み合わせることで実務向けの構成にできます。
RESTSharpは、REST API呼び出しを簡潔に書ける外部ライブラリです。プロジェクトで採用されている場合は便利ですが、まずは標準のHttpClientを理解するのがおすすめです。
初心者は、最初にHttpClient、System.Net.Http.Json、async/awaitを学ぶと、C# API連携の基礎が身につきます。
13-6. 初心者はどこから学べばよい?
初心者は、次の順番で学ぶと理解しやすいです。
まず、HTTPメソッド、ステータスコード、JSON、REST APIの考え方を学びます。次に、ASP.NET Core Web APIでGET、POST、PUT、DELETEを作ります。その後、Entity Framework Coreでデータベース連携を実装します。
続いて、HttpClientで外部APIを呼び出し、async/await、エラーハンドリング、ログ、設定管理、認証を学びます。
最初から完璧な設計を目指す必要はありません。まずは小さなC# APIを作り、動かしながら少しずつ実務的な構成に近づけることが大切です。
まとめ
C# APIを学ぶことで、Webサービス、業務システム、スマートフォンアプリ、クラウドサービスなど、さまざまなアプリケーションを連携できるようになります。
APIを作る側では、ASP.NET Core Web APIを使ってController、ルーティング、HTTPメソッド、ステータスコード、DTO、Entity Framework Core、認証、エラーハンドリングを理解することが重要です。
APIを呼び出す側では、HttpClient、JSON変換、async/await、IHttpClientFactory、外部APIのエラー処理を理解する必要があります。
初心者は、まずデータベースを使わない簡単なCRUD APIを作り、その後EF Coreでデータベース連携を追加し、さらにHttpClientで外部REST APIを呼び出す流れで学ぶと効率的です。
C# API開発では、動くだけでなく、保守しやすく、安全で、利用者に分かりやすいAPIを作ることが大切です。Controllerに処理を書きすぎない、DTOを使う、適切なステータスコードを返す、設定値やログを整える、認証・認可を適切に実装する、といった基本を押さえれば、実務でも使いやすいREST APIを構築できます。

