Blazor から Laravel の Web API 呼び出しの組み合わせ(商品一覧)

続き。

カテゴリ一覧で「カテゴリ」を選択したときに、商品一覧を表示します。商品はカテゴリの中に含まれているもので Web API のほうでは openapi.yaml で “api/categories/{id}” として定義しています。

  /categories/{id}:
    get:
      tags:
        - categories
      summary: カテゴリ詳細取得
      description: 指定されたIDのカテゴリ情報を取得
      parameters:
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Category'
        '404':
          $ref: '#/components/responses/NotFound'

実際のレスポンス(JSON形式)

{
    "data": {
        "id": 6,
        "name": "サイドメニュー",
        "description": "寿司と一緒に楽しめるサイドメニューです。",
        "created_at": "2026-05-15T03:00:01.000000Z",
        "updated_at": "2026-05-15T03:00:01.000000Z",
        "products": [
            {
                "id": 19,
                "name": "茶碗蒸し",
                "price": "280.00",
                "description": "なめらかな茶碗蒸し",
                "image_url": null,
                "created_at": "2026-05-15T03:00:01.000000Z",
                "updated_at": "2026-05-15T03:00:01.000000Z",
                "pivot": {
                    "category_id": 6,
                    "product_id": 19
                }
            },
            {
                "id": 20,
                "name": "枝豆",
                "price": "180.00",
                "description": "塩ゆで枝豆",
                "image_url": null,
                "created_at": "2026-05-15T03:00:01.000000Z",
                "updated_at": "2026-05-15T03:00:01.000000Z",
                "pivot": {
                    "category_id": 6,
                    "product_id": 20
                }
            }
        ]
    }
}

カテゴリの詳細情報を get で取ってきているのに、カテゴリの中に商品(product)の配列があるのはどうなの? という気がしないでもないのですが、カテゴリに紐づく商品の一覧が取得できます。これは書籍用に api 呼び出しが煩雑にならないようにしたのですが、実務的には “/api/products/category/{id}” のように /api/products のほうに紐づけたほうがよさそうです。

商品一覧を作る

Blazor で商品一覧を表示するための Products.razor を作ります。

  • パラメータは、”/products/category/{CategoryId:int}” のように渡される
  • [Parameter] public int CategoryId で受け取る
  • GetFromJsonAsync メソッドで受信した JSON 形式のデータを、Category クラスで受け取る

ところまで書いておきます。
画面への表示はシンプルに div タグで表示させているだけです。

@page "/products/category/{CategoryId:int}"
@rendermode InteractiveServer
@inject NavigationManager Navigation
@inject HttpClient Http
@inject IJSRuntime JSRuntime

<PageTitle>カテゴリ一覧</PageTitle>

<div class="container py-4">
    <div class="mb-4">
        <h2 class="fw-bold text-danger">🍣 商品一覧</h2>
        <p class="text-secondary">商品を選択してください</p>
    </div>

    <div class="row">
        @foreach (var it in products)
        {
            <div>@it.Id : @it.Name @it.Price</div>
        }
    </div>
</div>

@code {
    [Parameter] public int CategoryId { get; set; }

    class Product 
    {
        public int Id { get; set; }
        public string Name { get; set; } = "";
        public string Description { get; set; } = "";
        public string Price { get; set; } = "";
        public string? ImageUrl { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
    }
    class Category
    {
        public int Id { get; set; }
        public string Name { get; set; } = "";
        public string Description { get; set; } = "";
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
        public Product[] Products { get; set; } = [];

    }
    class CategoryResponse {
        public Category Data { get; set; } = default!;
    }

    private List<Product> products = new() ;

    protected override async Task OnInitializedAsync()
    {
        await onSearch();
    }

    private async Task onSearch()
    {
        System.Text.Json.JsonSerializerOptions JsonOptions = new()
        {
            PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.SnakeCaseLower
        };

        var res = await Http.GetFromJsonAsync<CategoryResponse>($"api/categories/{CategoryId}", JsonOptions);
        if (res != null)
            products = res.Data.Products.ToList();
    }
}

GetFromJsonAsync メソッドの戻り値を CategoryResponse クラスとして定義しないといけないのが、ちょっと厄介ですが、レスポンスの型チェックとして必要不可欠…というか、このあたりは Web API から提供される openapi.yaml から自動生成してしまうのがよいです。ここでは code ブロックに定義していますが、実際は models とかに突っ込めば ok です。

レイアウトを変更する

Claude Code を使ってレイアウトを修正して貰います。

<PageTitle>商品一覧</PageTitle>

<div class="container py-4">
    <div class="mb-4">
        <h2 class="fw-bold text-danger">🍣 商品一覧</h2>
        <p class="text-secondary">商品を選択してください</p>
    </div>

    @if (isLoading)
    {
        <div class="d-flex justify-content-center py-5">
            <div class="spinner-border text-danger" role="status">
                <span class="visually-hidden">読み込み中...</span>
            </div>
        </div>
    }
    else if (products.Count == 0)
    {
        <div class="alert alert-warning">商品が見つかりませんでした。</div>
    }
    else
    {
        <div class="row row-cols-1 row-cols-md-3 g-4">
            @foreach (var it in products)
            {
                <div class="col">
                    <div class="card h-100 shadow-sm border-0">
                        <div class="card-body">
                            <h5 class="card-title fw-bold">@it.Name</h5>
                            <p class="card-text text-secondary">@it.Description</p>
                        </div>
                        <div class="card-footer bg-white border-0 d-flex justify-content-between align-items-center">
                            <span class="fw-bold text-danger">¥@it.Price</span>
                            <button class="btn btn-danger btn-sm" @onclick="() => AddToCart(it)">カートに追加</button>
                        </div>
                    </div>
                </div>
            }
        </div>
    }
</div>

これで「カートに追加」ボタンをクリックすると、商品をカートに入れる準備ができました。AddToCart メソッドを実装すれば良い状態になっています。

@inject BlazorOrderApp.Services.CartService Cart

...
@code {
    ...
    private async Task AddToCart(Product product)
    {
        await Cart.AddAsync(product.Id, product.Name, product.Price);
    }
}

カート機能のメモリは、Blazor アプリケーション全体で共通して持つことになるので、ひと工夫が必要です。

Blazor の状態管理ということで、以下を使います。

ASP.NET Core Blazor 状態管理の概要 | Microsoft Learn
https://learn.microsoft.com/ja-jp/aspnet/core/blazor/state-management/?view=aspnetcore-10.0

書籍のほうは、この部分が抜けてしまったので、後日補足。

カテゴリー: 開発 パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

*