Help us understand the problem. What is going on with this article?

C#(ASP.NET core)でWeb APIを作ってみる(Hello World編)

More than 1 year has passed since last update.

はじめに

C#でWeb APIを作ろうとすると、core無しのASP.NETとcore付きのASP.NETがあるみたいですが、core付きのほうが新しそう、という理由だけで、ASP.NET coreでWeb APIの作り方を書いていこうかと思います。ちなみにバージョンは、ASP.NET core 2.1になります。

今回は、とにかくWeb APIを作って動かすやり方の話になります。そのため、プログラムの解説は全くしません。Web APIの話は1回で収まらないため、プログラムの解説は次回以降で書こうと思います。

目次

  • Hello World編 (ここ)
  • IISデプロイ編 
  • ルーティング編 (まだ)
  • リクエストパラメータ編 (まだ)
  • レスポンス編 (まだ)
  • 認証編 (まだ)
  • 認可編 (まだ)

準備するもの

  • Visual Studio 2017
    • これが無いと、ASP.NET core のプロジェクトが作れない
  • WinCurl
    • この記事の下のほうに、入手&導入方法があります。

作るAPI

例として作るAPIは、定番のCRUD4パターンを実装をしていきます。

API 説明 リクエストボディ レスポンスボディ ステータスコード
GET /api/todo/ すべてのToDoリストを取得する。 (なし) ToDoアイテムの配列 200
GET /api/todo/{id} {id}で指定したToDoアイテムを取得する。 (なし) ToDoアイテム 200
404({id}で指定したTodoアイテムが無い場合)
POST /api/todo/ ToDoを登録する ToDoアイテム Todoアイテム 201
PUT /api/todo/{id} {id}で指定したToDoアイテムを更新する。 Todoアイテム (なし) 204
404({id}で指定したTodoアイテムが無い場合)
DELETE /api/todo/{id} {id}で指定したToDoアイテムを削除する。 (なし) (なし) 204
404({id}で指定したTodoアイテムが無い場合)

Visual Studioでプロジェクトを作成する

(1) メニューの「ファイル」>「新規作成」>「プロジェクト...」を選択します。
2018-11-14_221330.png

(2) 「Web」から「ASP.NET Core Web アプリケーション」を選択します。プロジェクト名は何でもいいですが、今回の例ではTodoにしておきます。
2018-11-14_221432.png

(3) 続いて、プロジェクトのテンプレート選択画面から、上部にある「.NET Core」のバージョン「ASP.NET Core 2.1」を選択し、テンプレートは「空」を選択します。「Dockerサポートを有効にする」「HTTPS用の構成」はチェックを外して「OK」を押します。
2018-11-14_221450.png

ポート番号を変えておく(必須ではない)

ローカルでVisual Studioからデバック実行すると、デフォルトでランダムに設定されたポートで起動します。このままでもいいのですが、個人的に50000番台のポートを使っているのが気に喰わないので変えておきます。

(1) プロジェクト名(Todo)を右クリック>「プロパティ」でプロジェクトの設定画面を開き、「デバッグ」タブを選択すると、「アプリURL」があるので、ポート番号を変更します。番号は何番でもいいのですが、 http://localhost:9999 に変えておきます。
2018-11-14.png

実装する

プロジェクトの作成と設定は完了したので、プログラムを作っていきます。

モデルを追加する

モデルには、Todoアイテムを表すTodoItemクラスを作ります。

Modelsフォルダがないので、右クリック>「追加」>「新しいフォルダー」を選択し、Modelsと入力してフォルダを作っておきます。
2018-11-13_225834.png

Modelsフォルダを作ったら、そこを右クリック>「追加」>「クラス...」でTodoItemクラスを作ります。
2018-11-13_225948.png

TodoItemクラスの実装は、次のようにします。ただの構造体クラス(C#ではPOCOと呼ぶらしい)です。

TodoItem.cs
namespace Todo.Models
{
    public class TodoItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool IsDone { get; set; }
    }
}

コントローラーを追加し、メソッドを実装する(GETだけ)

続いてルーティングの定義と、APIの処理をするクラスを作ります。

プロジェクトを「空」で作ると Controllers フォルダもないので、Modelsのときと同様に、右クリック>「追加」>「新しいフォルダ」でフォルダを作っておきます。

フォルダを作ったら、Controllersフォルダを、右クリック>「追加」>「コントローラー...」を選択します。
2018-11-13_230317.png

コントローラーの種類を選択する画面では、「APIコントローラー - 空」を選択し、クラス名は TodoController にします。
2018-11-13_230451.png
2018-11-13_230506.png

TodoController クラスは次のように実装します。データは、本来はデータベースや他のWeb APIなどから取得しますが、今回はデーターベースを使わないので、コントローラークラスにハードコーディングしてしまいます。また、GETを受け取る2つのメソッド(/api/todo/api/todo/{id})も実装します。

TodoController.cs
...
using Todo.Models;

namespace Todo.COntrollers
{
    [Route("api/{controller}")]
    [ApiController]
    public class TotoController : ControllerBase
    {
        // Todoアイテムの初期データ。本来はデータベースなどから取得する。
        private static List<TodoItem> items = new List<TodoItem>() {
            new TodoItem() { Id = 1, Name = @"犬の散歩", IsDone = false, },
            new TodoItem() { Id = 2, Name = @"買い物", IsDone = true, },
            new TodoItem() { Id = 3, Name = @"本棚の修理", IsDone = false },
        };

        [HttpGet]
        public ActionResult<List<TodoItem>> GetAll()
            => items;

        [HttpGet("{id}", Name = "Todo")]
        public ActionResult<TodoItem> GetById(int id)
        {
            var item = items.Find(i => i.Id == id);
            if (item == null)
                return NotFound();
            return item;
        }
    }
}

Startup.csを変更する

空のプロジェクトの場合、StartUp.csに必要な起動処理が書かれていないので、これも実装します。ConfigureServices()Configure()メソッドの中身を次のように書き換えます。

Startup.cs
...
using Microsoft.AspNetCore.Mvc;

namespace Todo
{
    public class StartUp
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
                    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

試してみる1

これで、GETメソッドだけですが実装完了です。早速試してみましょう。

Web APIテスト用クライアントを導入する

GETメソッドならブラウザからの確認でもいいのですが、今後POSTやPUTなども試したいので、何か確認用ツールを導入します

RESTful APIをテストするときの定番ツールは curl であり、Windowsにも curl はあるのですが(WinCurl)、コマンドプロンプトからではどうがんばっても日本語をUTF-8で入力できない(表示はできる)ので、GUIのツールに頼るしかなさそうです。おそらくブラウザのプラグイン、Chrome の postman か Advanced Rest Client あたりになるかと思います。この記事では、curl の導入方法と、確認 curl のコマンドで書きますが、postman とか使う人は適当に読み替えてください。

WinCurlをインストールする

いちおう、WinCurlの導入方法を書いておきます。

https://curl.haxx.se/download.html へ行き、下のほうにある「Windows 64 bit」から、ダウンロードします。
2018-11-14.png

ダウンロードしたファイルは、ただのexe(インストーラーではない)なので、C:\Program Filesなど、適当なフォルダに解凍したフォルダごと置き、環境変数PATHを通しておきます(マイコンピューターを、右クリック>「プロパティ」で、「環境設定」>「詳細設定」タブ>「環境変数」のPATHに追加する)。

試す

Visual Studio上でF5を押して起動し、コマンドプロンプトを起動してcurlを実行します。F5を押すと、ブラウザが自動的に起動しますが、今は無視してください(じゃまなので、後で起動しないように設定を変更する)。オプションに -D - を付けて、レスポンスヘッダーも出すようにしておきます。APIの確認をするとき、レスポンスボディしか見ない人がいますが、ちゃんとレスポンスヘッダーも確認するようにしましょう。

> curl -D - -X GET "http://localhost:9999/api/todo"
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG8=?=
X-Powered-By: ASP.NET
Date: Wed, 14 Nov 2018 13:36:23 GMT

[{"id":1,"name":"犬の散歩","isDone":false},{"id":2,"name":"買い物","isDone":true},{"id":3,"name":"本棚の修理","isDone":false}]

> curl -D - -X GET "http://localhost:9999/api/todo/1"
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMQ==?=
X-Powered-By: ASP.NET
Date: Wed, 14 Nov 2018 13:40:05 GMT

{"id":1,"name":"犬の散歩","isDone":false}

> curl -D - -X GET "http://localhost:9999/api/products/0"
HTTP/1.1 404 Not Found
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMA==?=
X-Powered-By: ASP.NET
Date: Wed, 14 Nov 2018 13:40:28 GMT
Content-Length: 0

確認ポイント:

  • ステータスコード
    • ときどき、なんでも200を返すAPIがいる。
  • X-xxxヘッダー
    • サーバー情報がはいっているので、なるべくIISの設定を何とかして出さないようにしたほうがいい。今回はVisual Studio上でデバッグで動かしているので、関係ないですが。
  • Location
    • Createのとき、生成したリソースのURLが入る。この値がむちゃくちゃだったり、無かったりするときがある。
  • Content-Type
    • application/jsonになっているか。
  • Content-Length
    • ときどき、むちゃくちゃな値が入っているときがある。また、このヘッダーの代わりにTransfer-Encoding: chunkになっている場合がある(これ自体は問題ない)。Transfer-Encodingが受け取れない、残念なクライアントがたまにいる。

他のメソッドも実装する(POST, PUT, DELETE)

TodoControllerクラスに、POST, PUT, DELETE用のメソッドも追加していきましょう。

TodoController.cs
    [Route("api/{controller}")]
    [ApiController]
    public class TotoController : ControllerBase
    {
        ...

        [HttpPost]
        public IActionResult Create(TodoItem item)
        {
            // 新しいTodoItemのIdは、最大値+1にする
            // 本当はSQLでやる
            item.Id = items.Max(i => i.Id) + 1;
            items.Add(item);

            return CreatedAtRoute("Todo", new { id = item.Id }, item);
        }

        [HttpPut("{id}")]
        public IActionResult Update(int id, TodoItem item)
        {
            var target = items.Find(i => i.Id == id);
            if (target == null)
                return NotFound();

            target.Name = item.Name;
            target.IsDone = item.IsDone;

            return NoContent();
        }

        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            var n = items.RemoveAll(i => i.Id == id);
            if (n == 0)
                return NotFound();
            return NoContent();
        }
    }

試してみる2

デバッグ実行のとき、ブラウザ起動しないようにする

curl などツールを使う場合、いちいちブラウザが起動してうっとうしいので、起動しないように設定します。

プロジェクトを右クリックしてプロジェクトの設定を開き、「デバッグ」タブを選択すると、「ブラウザの起動」にチェックが入っているので、チェックをはずします。
2018-11-17_221234.png

試す

  • POST

ボディがある場合は、Content-Typeヘッダーを付けないと、エラーになります。
※注 コマンドプロンプトから日本語を入力する場合、エンコードがShift_JISになり、エラーになります。

> curl -D - -X POST -H "Content-Type: application/json" -d "{\"name\":\"旅行\", \"isDone\":false}" "http://localhost:9999/api/todo"
HTTP/1.1 201 Created
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Location: http://localhost:9999/api/Todo/4
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG8=?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:01:10 GMT

{"id":4,"name":"旅行","isDone":false}

> curl -D - -X GET "http://localhost:9999/api/todo"
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXFRvZG9cNA==?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:02:35 GMT

{"id":4,"name":"旅行","isDone":false}

ステータスコードが201で、Location ヘッダーがあることを確認しましょう。

  • PUT

※注 コマンドプロンプトから日本語を入力する場合、エンコードがShift_JISになり、エラーになります。

> curl -D - -X PUT -H "Content-Type: application/json" -d "{\"name\":\"犬の散歩\", \"isDone\":true}" "http://localhost:9999/api/todo/1"
HTTP/1.1 204 No Content
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMQ==?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:09:47 GMT

> curl -D - -X PUT -H "Content-Type: application/json" -d "{\"name\":\"ほげほげ\", \"isDone\":true}" "http://localhost:9999/api/todo/0"
HTTP/1.1 404 Not Found
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMA==?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:10:19 GMT
Content-Length: 0
  • DELETE
> curl -D - -X DELETE "http://localhost:9999/api/todo/1"
HTTP/1.1 204 No Content
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMQ==?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:11:13 GMT

> curl -D - -X DELETE "http://localhost:9999/api/todo/0"
HTTP/1.1 404 Not Found
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcQXBwbGljYXRpb25cdnNwcm9qZWN0c1xUb2RvXFRvZG9cYXBpXHRvZG9cMA==?=
X-Powered-By: ASP.NET
Date: Sat, 17 Nov 2018 13:11:33 GMT
Content-Length: 0

まとめ

今回は、動かすことに集中しプログラムの解説を全くしなかったため、プログラムに関しては意味不明だったと思います(特にルーティングとレスポンスの生成)。プログラムの解説は次回以降で行っていく予定です。

Web API は core になって、MVC の枠組みの中の1つとなってしまい、いろいろ作るものが多いという印象です。これが複雑さを上げているように思います。

参考文献、サイト

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away