WebSurfer's Home

Filter by APML

ASP.NET Core Minimal API

by WebSurfer 6. July 2025 15:56

今さらながらですが、ASP.NET Core に Minimal API という軽量・高速 HTTP API を構築する簡単な手法があるということを知ったので、少しだけですが試してみました。以下に備忘録として試したことを書いておきます。

Minimal API からデータ取得

Minimal API というのは、Microsoft のドキュメント「Minimal API の概要」に書いてありますように、Controller を使わないで最小のコードと構成で REST API を構築するもので、Controller のアクションメソッドに代えて Program.cs のミドルウェアで要求を処理して応答を返します。

基本的な作り方は Microsoft のチュートリアル「チュートリアル: ASP.NET Core を使って最小 API を作成する」にありましたので、それを参考に「API コードを追加する」のセクションのところまで作ってみました。

作り方については、プロジェクトの作成からサンプル REST API を構築するための詳しい方法までチュートリアルに述べられていますのでそちらを見てください。手抜きでスミマセンが、チュートリアルには十分な情報が提供されており、追加で書くことなどもありませんので。

チュートリアルの「API コードを追加する」のセクションまで進めば、GET, POST, PUT, DELETE 要求を受けて JSON 文字列を返す REST API が完成します。

上の画像は、検証のため別の ASP.NET Core MVC アプリに作成した REST API を呼び出すページを追加して、ボタンクリックで JavaScript の fetch を使って要求を出し、JSON 文字列として返される応答を表示したものです。そのコードはこの記事の下の方に参考に載せておきます。

また、検証に使用した呼び出し側のアプリはクロスオリジンになるので Minimal API では CORS の機能を有効にする必要がありますが、その方法を以下に書いておきます。

(1) CORS の機能を実装

先の記事「Web API に CORS 実装 (CORE)」に書いた Controller を使う普通の ASP.NET Core Web API と同様に、Program.cs に AddCors と UseCors を追加すれば CORS の機能は働くようになります。具体例は以下の通りです。

namespace MinimalAPI
{
    public class Program
    {
        // CORS の機能を追加
        const string MyAllowAnyOrigins = "_myAllowAnyOrigins";

        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // CORS の機能を追加
            builder.Services.AddCors(options =>
            {
                options.AddPolicy(name: MyAllowAnyOrigins,
                                  policy =>
                                  {
                                      policy.AllowAnyOrigin()
                                            .AllowAnyHeader()
                                            .AllowAnyMethod();
                                  });
            });

            // ・・・中略・・・

            var app = builder.Build();

            // CORS の機能を追加
            app.UseCors(MyAllowAnyOrigins);

            // ・・・中略・・・            
        }
    }

Microsoft のドキュメント「CORS(異なるオリジン間でのリソース共有) 」にも説明がありますが、そのドキュメントには書いてない AllowAnyHeader() と AllowAnyMethod() は Preflight リクエストに必要なので注意してください。

また、そのドキュメントには "CORS は、[EnableCors] 属性により、または RequireCors メソッドを使用して宣言できます" と書いてありますが、自分が試した限りではそれらは不要でした。

(2) 呼び出し側の View のコード

検証のため、別の ASP.NET Core MVC アプリに作成した View のコードです。ボタンクリックで JavaScript の fetch を使って要求を出し、JSON 文字列として返される応答を表示します。

@{
    ViewData["Title"] = "MinimalApiCors";
}

<h1>MinimalApiCors</h1>

<input type="button" value="READ ALL" onclick="minimalApiGet();" />
<input type="button" value="READ 1" onclick="minimalApiGet1();" />
<input type="button" value="READ COMPLETE" onclick="minimalApiGetCompleted();" />
<input type="button" value="UPDATE 1" onclick="minimalApiPut1();" />
<input type="button" value="DELETE 1" onclick="minimalApiDelete1();" />
<input type="button" value="CREATE" onclick="minimalApiPost();" />

<ul id="heroes"></ul>

@section Scripts {
    <script type="text/javascript">
        //<![CDATA[

        const url = "https://localhost:44374/todoitems"; // IIS Express
        const elem = document.querySelector("#heroes");

        const minimalApiGet = async () => {
            const response = await fetch(url);
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                for (let i = 0; i < data.length; i++) {
                    elem.insertAdjacentHTML("beforeend",
                        `<li>${data[i].id}: ${data[i].name}, ${data[i].isComplete}</li>`);
                }
            } else {
                elem.innerHTML = "失敗";
            }
        };

        const minimalApiGet1 = async () => {
            const response = await fetch(url + "/1");
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                elem.insertAdjacentHTML("beforeend",
                    `<li>${data.id}: ${data.name}, ${data.isComplete}</li>`);
            } else {
                elem.innerHTML = `失敗 (${response.status})`;
            }
        };

        const minimalApiGetCompleted = async () => {
            const response = await fetch(url + "/complete");
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                for (let i = 0; i < data.length; i++) {
                    elem.insertAdjacentHTML("beforeend",
                        `<li>${data[i].id}: ${data[i].name}, ${data[i].isComplete}</li>`);
                }
            } else {
                elem.innerHTML = "失敗";
            }
        };

        const minimalApiPut1 = async () => {
            const params = {
                method: "PUT",
                body: '{"Id":1,"Name":"Updated animal","isComplete":true}',
                headers: { 'Content-Type': 'application/json' }
            }
            const response = await fetch(url + "/1", params);
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                elem.insertAdjacentHTML("beforeend",
                    `<li>${data.id}: ${data.name}, ${data.isComplete} - Updated</li>`);
            } else {
                elem.innerHTML = `失敗 (${response.status})`;
            }
        };

        const minimalApiDelete1 = async () => {
            const params = {
                method: "DELETE"
            }
            const response = await fetch(url + "/1", params);
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                elem.insertAdjacentHTML("beforeend",
                    `<li>${data.id}: ${data.name}, ${data.isComplete} - Deleted</li>`);
            } else {
                elem.innerHTML = `失敗 (${response.status})`;
            }
        };

        const minimalApiPost = async () => {
            const params = {
                method: "POST",
                body: '{"name":"Posted animal","isComplete":true}',
                headers: { 'Content-Type': 'application/json' }
            }
            const response = await fetch(url, params);
            if (response.ok) {
                const data = await response.json();
                elem.innerHTML = "";
                elem.insertAdjacentHTML("beforeend",
                    `<li>${data.id}: ${data.name}, ${data.isComplete} - Inserted</li>`);
            } else {
                elem.innerHTML = "失敗";
            }
        };

        //]]>
    </script>
}

Tags: , , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  July 2025  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar