ASP.NET Web APIの簡単なサンプル・コードを見てみよう。そのコードとは、Visual Studio 2012に搭載されているASP.NET Web APIプロジェクト・テンプレートから生成される初期のひな型コード(以降、プロジェクト・テンプレート・コード)だ。このテンプレートには、すでにいくつかのWeb APIが定義されている。
HTTPサービスを提供するフレームワークなので、実際に処理を呼び出すにはHTTPリクエストを送信するクライアントが必要だ。「A Simple Test Client for ASP.NET Web API」というASP.NET Web API用のデバッグを行うためのパッケージも公開されているが、ここでは「Fiddler2」を使用する。IDEはVisual Studio Express 2012 for Web、言語はVisual C#を使用する。
Visual Studio Express 2012 for Webを開き、(メニューバーから)[ファイル]−[新しいプロジェクト]を選択し、ASP.NET MVC 4のプロジェクト・テンプレートを選択してプロジェクト作成を進め(次の画面を参照)、その途中で表示されるダイアログで[Web API]を選択する。
作成されるプロジェクトは、ASP.NET MVCとASP.NET Web APIを組み合わせたものである。
作成直後に[F5]キーを押してデバッグを実行すると、次の画面のようにトップ・ページが表示される。これはASP.NET MVCにより生成されたページである。
プロジェクト・テンプレート・コードには、ASP.NET MVCのコントローラやビュー、APIヘルプ・ページ関連のファイルが含まれているが、肝心のASP.NET Web APIのコードは2箇所だ。
「ルーティングの設定」と「APIコントローラ」である。ルーティングの設定から見てみよう。なお、本記事ではコードの変更は行わない。
ルーティングの設定は、App_StartフォルダのWebApiConfig.csファイルに(次のように)記述されている。
using System.Web.Http;
namespace ApiTry
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// ……コメント省略
//config.EnableQuerySupport();
// ……コメント省略
config.EnableSystemDiagnosticsTracing();
}
}
}
このRegisterメソッドの初めに、MapHttpRouteメソッドで記述されているコードが、ルーティングの設定だ。この設定は必ず必要となる。
MapHttpRouteメソッドの引数、routeTemplateに指定されている文字列(=URLテンプレート。この例では「api/{controller}/{id}」)に当てはまるリクエストを、APIコントローラのメソッドにマッピングする。このルーティングの設定は、URLの一部である「{controller}」の箇所に指定されたコントローラ名と同じAPIコントローラにマッピングされることを表す。例えば「api/values/1」というURLでHTTPのGETメソッドを呼び出した場合は、ValuesControllerクラス(=コントローラ)のGet(id)メソッドが呼び出され、引数として「1」が渡される。
defaultsパラメータの引数のidプロパティに指定されている「RouteParameter.Optional」は、「id」が省略可能なパラメータであることを表している。つまり、URLの一部である「{id}」の値が設定されていてもいなくても、このルーティング設定が適用される。具体的には例えば「api/values」というURLでHTTPのGETメソッドを呼び出せば、ValuesControllerクラスのGetメソッド(引数なし)が呼び出されるということである。
このルーティング設定に対応するURLと、マッピングされるAPIコントローラとパラメータの例を以下の表に記す。
URL | マッピングされるAPIコントローラ・クラス | パラメータidの値 |
---|---|---|
http://localhost:XXXX/api/values | ValuesController | 無し |
http://localhost:XXXX/api/values/3 | ValuesController | 3 |
http://localhost:XXXX/api/books | BooksController | 無し |
http://localhost:XXXX/api/room/2 | RoomController | 2 |
プロジェクト・テンプレート・コードのルーティング設定におけるURLの例と、それにマッピングされるAPIコントローラの一覧 |
HttpConfigurationクラス(System.Web.Http名前空間)に対してルーティング設定を行っているが、そのほかの設定もこのRegisterメソッド内で行える。上記のコード例にもあるEnableQuerySupportメソッドやEnableSystemDiagnosticsTracingメソッドはその一例だ(ここでは詳説を省く)。
基本的にASP.NET Web APIの設定を行うときは、このHttpConfigurationクラスに対して処理を書くことになるだろう。
このRegisterメソッドは、(次のコード例のように)Global.asax.csファイルのApplication_Startメソッドにより実行される((1))。なおRegisterメソッドは、アプリケーション起動時に必ず実行されなければならない。
namespace ApiTry
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration); //(1)
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
以上が、プロジェクト・テンプレート・コードにおける、ルーティングの設定だ。パラメータの正規表現や、HTTPメソッドの制約なども追加できるが、詳細は次回以降の記事で解説する。
次は、APIコントローラのコードを見てみよう。
ControllersフォルダにValuesControllerクラスのファイルが追加されているので開いてみよう(同フォルダにあるHomeControllerクラスのファイルは、ASP.NET MVCのコントローラ・クラスのためのものである)。
先ほども説明したように、このValuesControllerクラスが、ASP.NET Web APIにおける「APIコントローラ」と呼ばれるものである。APIコントローラは、一般的にはApiControllerクラス(System.Web.Http名前空間)を継承し、サフィックスとして「Controller」を付ける(厳密に言うと、APIコントローラはApiControllerクラスを継承しなくても、IHttpControllerインターフェイス(System.Web.Http.Controllers名前空間)を実装していればよい)。クラス内には、エンドポイントとなるメソッドがいくつか定義されている。
ValuesControllerクラスのコードは以下のとおりだ。
using System.Collections.Generic;
using System.Web.Http;
namespace ApiTry.Controllers
{
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
}
それぞれのメソッドの上に、対応するURLとHTTPリクエストのメソッドの例がすでにコメントとして記述されている。
だが、先ほどのルーティング設定では、コントローラの指定は行ったが、メソッドの指定は行わなかった。なぜこのようにURLにマッピングされているか?
答えは、メソッドの選択は、HTTPリクエストのメソッド(GETやPOSTなど)により行われるからである。
HTTPリクエストのメソッドがGETの場合は「Get」で始まるメソッドが、POSTである場合は「Post」で始まるメソッドが、というふうに、HTTPリクエスト・メソッドと、APIコントローラのメソッドの名前が対応している場合にマッピングされる。例として、このValuesControllerクラスのGetメソッドの名前を、「GetValues」に変更したとしてもマッピングは変わらず動作する。
また、ValuesControllerクラスには、引数の違うGetメソッドが2つ定義されている。
これは、HTTPリクエストのURLで、先ほどのルーティングで設定したURLテンプレート「api/{controller}/{id}」の{id}に当たる部分が定義されているかいないかの違いによる。
上記のコードの「[FromBody]」は、引数の値がHTTPリクエストのBodyの値であることを表す。
以上のように細かいルールや設定が存在するが、取りあえず今回は「エンドポイントを定義するにはAPIコントローラを用意し、メソッドを定義する」とだけ覚えておいてほしい。
コードの確認は以上だ。[F5]キーでデバッグを開始した後、Fiddler2を起動し、各APIを呼び出してみよう。
HTTP GETメソッド: ValuesControllerクラスのGetメソッド(引数なし)にマッピング
まずは、以下のようなHTTPリクエストを送信する。
HTTPメソッド | GET |
---|---|
URL | http://localhost:XXXX/api/values/ |
このHTTPリクエストは、ValuesControllerクラスの引数無しのGetメソッドにマッピングされる。
なお、URLの「localhost」の後ろの「XXXX」という値は、起動されたブラウザのURL欄にある値と同じものに置き換えて指定する。
Fiddler2でHTTPリクエストを作成するには、次の画面で示すように、まず[Composer]タブをクリックする((1))。
HTTPメソッドの欄には「GET」((2))を、URLには「http://localhost:xxxx/api/values」((3))を入力する。入力した後、[Execute]ボタン((4))をクリックする。これにより、HTTPリクエストが送信される。
送信されたHTTPリクエストは、次の画面に示す左の欄((5))に一覧として表示される。今、送信したリクエスト内容に当たる最後の行を選択し、[Inspectors]タブ((6))をクリックしよう。
すると、右側の上部にはHTTPリクエストについて、下部ではHTTPレスポンスについての情報が表示される。下部の[Raw]タブ((7))をクリックし、HTTPレスポンスの中身を確認してみよう。
最後の行に「["value1","value2"]」と表示されているはずだ((8))。これは、ValuesControllerクラスの引数無しのGetメソッドの戻り値である。IEnumerable<string>型の値が、JSON型のデータに変換されてHTTPレスポンスに格納されていることを表している。
HTTP GETメソッド: ValuesControllerクラスのGetメソッド(引数あり)にマッピング
試しに、もう一方の引数ありのGetメソッドを、以下のようなHTTPリクエストで呼び出してみよう。
HTTPメソッド | GET |
---|---|
URL | http://localhost:XXXX/api/values/5 |
2回目のHTTPリクエスト(引数ありのGetメソッドにマッピング) |
2回目のHTTPリクエストは、URLの末尾に「5」とidを指定する。このHTTPリクエストは、ValuesControllerクラスの引数ありのGetメソッドにマッピングされる。
先と同じ方法で、HTTPレスポンスのBodyの値を確認してみると、「"value"」と表示されるはずだ。さらに、引数ありのGetメソッドにブレークポイントを設定してみてほしい。すると次の画面のように、引数のidに、URLで指定した「5」が代入されていることが確認できるはずだ。
HTTP POSTメソッド: ValuesControllerクラスのGetメソッド(引数なし)にマッピング
次は、Postメソッドを呼び出してみよう。Getメソッドのときとは違い、HTTPリクエストのBodyに値を設定する必要がある。
HTTPリクエストは以下のとおりだ。
HTTPメソッド | POST |
---|---|
URL | http://localhost:XXXX/api/values/ |
HTTPヘッダ | Content-Type : application/x-www-form-urlencoded |
Body | =hello |
3回目のHTTPリクエスト(引数なしのPostメソッドにマッピング) |
3回目のHTTPリクエストは、HTTPヘッダとBodyの値を設定する。このリクエストは、ValuesControllerクラスのPostメソッドにマッピングされる。
HTTPメソッドとURLについては、先ほどと同じなのでFiddler2での指定方法の説明は省略する。HTTPヘッダとBodyの設定方法は、以下のとおりだ。
HTTPメソッド欄で「POST」を選択すると((9))、下部に[Request Body]入力欄が表示される((10))。この欄に「=hello」と入力する。
また、HTTPヘッダ((11))に、「Content-Type : application/x-www-form-urlencoded」を入力する。
最後に[Execute]をクリックして、HTTPリクエストを送信してみよう。
また、そのときにPostメソッドにブレークポイントを設定し、引数のvalueに「hello」という文字列が代入されていることを確認してほしい(次の画面はその例)。
次は、Getメソッドのときと同じように、HTTPレスポンスの内容を確認してみよう。
Bodyの値は格納されておらず、先頭に「204 No Content」((12))と表示されているはずだ。これは、HTTPステータス・コードの1つで、処理には成功したが、返す値はないことを表している。
ValuesControllerクラスのPostメソッドのように、戻り値がvoidの場合は、ステータス・コード「204 No Content」が返される。
以上、GetメソッドとPostメソッドに対応するAPIを、Fiddler2を使って呼び出した。
HTTP PUTメソッドと、HTTP DELETEメソッド
PutメソッドとDeleteメソッドにおいても、同じように呼び出せるので、試してみてほしい。それぞれに対応するHTTPリクエストの例を、以下に記載しておく。
HTTPメソッド | PUT |
---|---|
URL | http://localhost:XXXX/api/values/3 |
HTTPヘッダ | Content-Type : application/x-www-form-urlencoded |
Body | =newValue |
HTTPリクエスト(Putメソッドにマッピング) |
HTTPメソッド | DELETE |
---|---|
URL | http://localhost:XXXX/api/values/4 |
HTTPリクエスト(Deleteメソッドにマッピング) |
HTTPメソッドがDELETEの場合は、HTTPリクエストのBodyに値を設定する必要はない。
お気づきかと思うが、ValuesControllerクラスのGet/Post/Put/Deleteのメソッドは、それぞれデータの取得/追加/更新/削除を想定したAPIのメソッドである。
パラメータidを用いてURLでリソースを表し、HTTPメソッドによってその操作を指示する、これはRESTfulなHTTPサービスの特徴の1つである。
本稿では、ASP.NET Web APIがRESTfulなHTTPサービスを構築するためのフレームワークであることを説明した。
最後のHello, Worldのコードは、String型という単純な値のやりとりを行うAPIの例だが、実際は、データのオブジェクトを使い、APIコントローラでは、取得・追加・更新・削除などの処理を行う。また、条件によっては返すHTTPレスポンスの制御が必要になってくる。
次回は、そのデータの操作について、RESTfulなAPIを実装する方法も含めて解説を行う予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.