0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ASP.NET Core Web API + React + TypeScript(vite)】書籍管理システム設計 ④ 詳細設計書(内部設計)

0
Last updated at Posted at 2026-07-27

本記事は 書籍管理システム設計(全4回)シリーズの ④ です。

📚 シリーズ全記事(全4回)

  1. 【ASP.NET Core Web API + React + TypeScript(vite)】書籍管理システム設計 ① 環境構築手順書
  2. 【ASP.NET Core Web API + React + TypeScript(vite)】書籍管理システム設計 ② 要件定義書
  3. 【ASP.NET Core Web API + React + TypeScript(vite)】書籍管理システム設計 ③ 基本設計書(外部設計)
  4. 【ASP.NET Core Web API + React + TypeScript(vite)】書籍管理システム設計 ④ 詳細設計書(内部設計)(この記事)

項目 内容
文書名 詳細設計書
システム名 書籍管理システム(Book Manager)
版数 1.0
作成日 2026-07-24
関連文書 01_要件定義書.md / 02_基本設計書.md

改訂履歴

日付 改訂内容 作成者
1.0 2026-07-24 初版作成(実装済みソースに基づく)

1. はじめに

本書は基本設計書に基づき、書籍管理システムの内部構造(クラス・メソッド・DB物理仕様・処理フロー)を実装レベルで定義する。


2. 全体構成

2.1 レイヤ構成

[ブラウザ] ─ App.tsx(表示・状態) ─ api.ts(HTTPクライアント)
                                      │  /api/*(Viteプロキシ)
                                      ▼
[API] BooksController(コントローラ) ─ AppDbContext(EF Core) ─ SQLite

2.2 ファイル構成と責務

区分 ファイル 責務
API api/Models/Book.cs 書籍エンティティ定義
API api/Data/AppDbContext.cs DbContext・DbSet・シード定義
API api/Controllers/BooksController.cs REST エンドポイント実装
API api/Program.cs DI 登録・ミドルウェア・起動
API api/Migrations/* スキーマ・シードのマイグレーション
Web web/src/api.ts 型定義・API 呼び出し関数
Web web/src/App.tsx 画面コンポーネント・状態管理
Web web/vite.config.ts 開発サーバ・プロキシ設定

3. バックエンド詳細設計

3.1 クラス構成図

3.2 Book モデル(api/Models/Book.cs

プロパティ 初期値 説明
Id int 0 主キー(EF 規約により自動採番)
Title string "" タイトル
Author string "" 著者
Year int 0 出版年
IsBorrowed bool false 貸出状態
public class Book
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public string Author { get; set; } = "";
    public int Year { get; set; }
    public bool IsBorrowed { get; set; }
}

3.3 AppDbContext(api/Data/AppDbContext.cs

  • DbSet<Book> Books を公開。
  • OnModelCreating にて HasData でシードデータ5件を定義。
  • コンストラクタで DbContextOptions<AppDbContext> を受け取る(DI)。
public DbSet<Book> Books => Set<Book>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<Book>().HasData(
        new Book { Id = 1, Title = "吾輩は猫である", Author = "夏目漱石", Year = 1905, IsBorrowed = false },
        new Book { Id = 2, Title = "羅生門",         Author = "芥川龍之介", Year = 1915, IsBorrowed = true  },
        new Book { Id = 3, Title = "人間失格",       Author = "太宰治",     Year = 1948, IsBorrowed = false },
        new Book { Id = 4, Title = "雪国",           Author = "川端康成",   Year = 1937, IsBorrowed = true  },
        new Book { Id = 5, Title = "こころ",         Author = "夏目漱石",   Year = 1914, IsBorrowed = false }
    );
}

3.4 BooksController(api/Controllers/BooksController.cs

  • 属性:[ApiController] / [Route("api/[controller]")] → 実パスは /api/books
  • 依存:コンストラクタ注入で AppDbContext _db を受け取る。
メソッド HTTP ルート 引数 戻り値 処理概要 ステータス
GetAll GET /api/books なし IEnumerable<Book> Books.ToListAsync() 200
Get GET /api/books/{id} int id ActionResult<Book> FindAsync(id)。無ければ NotFound 200 / 404
Create POST /api/books Book book ActionResult<Book> AddSaveChangesAsyncCreatedAtAction 201
Update PUT /api/books/{id} int id, Book book IActionResult id 不一致は BadRequest。Entry(book).State = Modified → 保存 204 / 400
Delete DELETE /api/books/{id} int id IActionResult FindAsync → 無ければ NotFound、あれば Remove → 保存 204 / 404
[HttpGet]
public async Task<IEnumerable<Book>> GetAll() => await _db.Books.ToListAsync();

[HttpGet("{id}")]
public async Task<ActionResult<Book>> Get(int id) =>
    await _db.Books.FindAsync(id) is { } b ? b : NotFound();

[HttpPost]
public async Task<ActionResult<Book>> Create(Book book)
{
    _db.Books.Add(book);
    await _db.SaveChangesAsync();
    return CreatedAtAction(nameof(Get), new { id = book.Id }, book);
}

[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, Book book)
{
    if (id != book.Id) return BadRequest();
    _db.Entry(book).State = EntityState.Modified;
    await _db.SaveChangesAsync();
    return NoContent();
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
    if (await _db.Books.FindAsync(id) is not { } b) return NotFound();
    _db.Books.Remove(b);
    await _db.SaveChangesAsync();
    return NoContent();
}

3.5 Program.cs(起動・DI・ミドルウェア)

処理 内容
AddControllers() コントローラを登録
AddDbContext<AppDbContext>(UseSqlite("Data Source=books.db")) EF Core + SQLite を DI 登録
AddOpenApi() OpenAPI 定義生成を登録
MapOpenApi() / MapScalarApiReference() 開発環境のみ OpenAPI・Scalar を公開
UseAuthorization() 認可ミドルウェア(現状はポリシーなし)
MapControllers() ルーティング割当

※ HTTP 運用のため UseHttpsRedirection() は使用しない。

3.6 処理シーケンス

登録(POST)

更新(PUT)/削除(DELETE)


4. データベース詳細設計

4.1 物理テーブル定義(Books)

カラム 型(SQLite) NULL 制約 説明
Id INTEGER NOT NULL PRIMARY KEY / AUTOINCREMENT 主キー
Title TEXT NOT NULL タイトル
Author TEXT NOT NULL 著者
Year INTEGER NOT NULL 出版年
IsBorrowed INTEGER NOT NULL 貸出状態(0/1)

4.2 DDL(Init マイグレーション生成)

CREATE TABLE "Books" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Books" PRIMARY KEY AUTOINCREMENT,
    "Title" TEXT NOT NULL,
    "Author" TEXT NOT NULL,
    "Year" INTEGER NOT NULL,
    "IsBorrowed" INTEGER NOT NULL
);

4.3 マイグレーション一覧

マイグレーション名 内容
1 Init Books テーブル作成
2 SeedBooks 初期データ5件の投入(HasData)

4.4 初期データ(シード)

Id Title Author Year IsBorrowed
1 吾輩は猫である 夏目漱石 1905 false
2 羅生門 芥川龍之介 1915 true
3 人間失格 太宰治 1948 false
4 雪国 川端康成 1937 true
5 こころ 夏目漱石 1914 false

5. フロントエンド詳細設計

5.1 コンポーネント構成

  • エントリ:main.tsxApp を描画(StrictMode)。
  • 画面:App.tsx の単一コンポーネント。
  • 通信:api.ts に集約。

5.2 api.ts(型・関数仕様)

名称 シグネチャ 説明
Book interface 書籍の型(id, title, author, year, isBorrowed)
getBooks () => Promise<Book[]> 一覧取得。!ok 時に例外
createBook (b: Omit<Book,"id">) => Promise<Book> 登録。登録済み Book を返す
updateBook (b: Book) => Promise<void> 更新(PUT /api/books/{b.id})
deleteBook (id: number) => Promise<void> 削除
  • ベースパス定数:const BASE = "/api/books";(相対パス=プロキシ経由)。
  • 各関数はレスポンス !r.ok の場合に Error を送出する。

5.3 App.tsx(状態・関数)

状態(useState)

状態 用途
books Book[] 一覧データ
form FormState 新規登録フォーム(title/author/year を文字列で保持)
editingId number | null 編集中の行 ID(null は非編集)
editForm FormState 編集中の入力値
loading boolean 読み込み中フラグ
error string | null エラーメッセージ

関数

関数 処理
load 一覧取得。取得失敗時は error を設定
add タイトル必須チェック→登録→フォーム初期化→再取得。年未入力は当年
startEdit(b) 対象行を編集モードにし editForm を初期化
cancelEdit 編集モード解除
saveEdit(b) 既存 Book に編集値を上書きして更新→再取得
toggleBorrow(b) isBorrowed を反転して更新→再取得
remove(id) 削除→再取得
  • 初期表示:useEffect(() => { load(); }, []) で一覧取得。

5.4 編集モードの状態遷移

一覧表示(editingId=null)
   │ startEdit(b):editingId=b.id, editForm=bの値
   ▼
行編集モード
   │ saveEdit:PUT→cancelEdit→load
   │ cancelEdit:editingId=null
   ▼
一覧表示

5.5 vite.config.ts(プロキシ)

server: {
  proxy: {
    '/api': 'http://localhost:5000',
  },
}
  • /api 始まりのリクエストを API(5000)へ転送。これにより CORS 不要。

6. 設定・環境詳細

6.1 ポート・起動プロファイル

対象 ポート 設定
API 5000(HTTP) Properties/launchSettings.json の http プロファイル(http 単一)
Web 5173(HTTP) Vite 既定

6.2 使用パッケージ

区分 パッケージ バージョン
NuGet Microsoft.AspNetCore.OpenApi 10.0.10
NuGet Microsoft.EntityFrameworkCore.Sqlite 10.0.10
NuGet Microsoft.EntityFrameworkCore.Design 10.0.10
NuGet Scalar.AspNetCore 2.16.16
npm react / react-dom 19.2.8
npm typescript 6.0.3
npm vite 8.1.5
npm @vitejs/plugin-react 6.0.4
npm @types/react / @types/react-dom 19.2.17 / 19.2.3

6.3 起動手順

# API
cd api && dotnet run --launch-profile http     # http://localhost:5000 , UI: /scalar
# Web
cd web && npm run dev                           # http://localhost:5173

6.4 DB 再構築手順

cd api && dotnet ef database update             # Init→SeedBooks を適用(シード自動投入)

7. エラーハンドリング詳細

事象 挙動
API 該当データなし(Get/Delete) 404 Not Found
API 更新時 id 不一致 400 Bad Request
Web 一覧取得の HTTP エラー/通信失敗 error 状態にメッセージを設定し画面表示
Web タイトル未入力 追加ボタンを非活性化し登録を抑止

8. 留意事項・既知の警告

  • ビルド時に NU1903 警告が出力される(推移的依存 Microsoft.OpenApi 2.0.0SQLitePCLRaw.lib.e_sqlite3 の脆弱性告知)。動作には影響しないが、必要に応じ該当パッケージを更新する。
  • 更新(PUT)は EntityState.Modified による全項目上書き方式であり、部分更新(PATCH)は未対応。
  • 単一利用者前提のため、同時更新の競合制御(楽観ロック等)は未実装。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?