ASP.NET WEB API ルーティングについていろいろ
ルーティング基本
WEB API において、アクションメソッドへのマッピングの基本は、
HTTP メソッド名から始まるメソッドへマッピングされることです。
HTTP POST だったら、POST..から始まるメソッドへ、
HTTP GET だったら、GET...から始まるメソッドへマッピングされます。
例↓
public class ValuesController : ApiController { // GET ~/api/values/ public void Get() { } // POST ~/api/values/ public void Post() { } // PUT ~/api/values/ public void Put() { } }
後ろの名前はなんでもOK
HTTP メソッド名から始まれば、後ろの名前はなんでもOKです。
GetHogeHoge という名前のメソッドでも、
GET ~/api/{controller名}/ でマッピングされます。
(※ MVC のように ~/api/{controller名}/HogeHoge ではマッピングされないので注意)
public class ProductsController : ApiController { // GET ~/api/products/ public String GetHogeHoge() { } }
アクションメソッド属性をつける
メソッド名が、HTTP メソッド名から始まらなくても
[HttpGet] や、[HttpPost] 等の属性をつければマッピング可能です。
例えば、FindHoge というメソッド名でも、[HttpGet] という属性をつければ、
GET ~/api/{controller名}/ でマッピングされます。
public class ProductsController : ApiController { // GET ~/api/products/ [HttpGet] public String FindHoge() { } }
次に重要なのは、アクションメソッドの引数
アクションメソッドのマッピングは、引数も重要な条件になります。
下の例の様に、メソッドが、
GetHoge(string name); の1つしかない場合、
GET ~/api/products/ はマッピングはされません。
GET ~/api/products/?name=taro だとマッピングされます。
public class ProductsController : ApiController { // 誤:GET ~/api/products/ // 正:GET ~/api/products/?name={0} [HttpGet] public String GetHoge(string name) { } }
ちなみに、誤である GET ~/api/products/ を実行すると、
404 Not Found で下のようなレスポンスが返ってきます。
もし、GetHoge(); というメソッドが追加されれば、
GET ~/api/products/ は GetHoge(); へ、
GET ~/api/products/?name={0} は、GetHoge(String name); へ
マッピングされます。
極端にすると、下の例のように
メソッド名は無視したオーバーロードのようなマッピングになります。
public class ProductsController : ApiController { // GET ~/api/products/ public String GetHoge() { } // GET ~/api/products/?name={0} public String GetHogeHoge(String name) { } // GET ~/api/products/?message={1} public String GetHogeHogeHoge(String message) { } }
引数の名前も条件に
引数(パラメータ)の名前によっても、マッピングは変わってきます。
下の例の用に、GET でマッピングされるメソッドが2つあり、
引数の名前が同じ場合、GET ~/api/products/?name={0} のマッピングは失敗します。
GET と 引数でメソッドを選択するため、どちらのメソッドにも当てはまってしまうからです。
public class ProductsController : ApiController { // GET ~/api/products/?name={0} は下の2つにはマッピングされない public String GetHoge(String name) { } public String GetHogeHoge(String name) { } }
ちなみに、このときのレスポンスは、
500 Internal Server Error で下のようなレスポンスが返ってきます。
アクション名を指定する
上記の場合で、どうしてもマッピングを振り分けたい場合は、
お馴染みのルーティング設定で、アクション名を指定します。
下の例のように、それぞれのURL でマッピングを定義する場合は・・・
public class ProductsController : ApiController { // GET ~/api/products/hoge?name={0} public String GetHoge(String name) { } // GET ~/api/products/hogehoge?name={0} public String GetHogeHoge(String name) { } }
WebApiConfig.cs にて、このようにルーティングを設定します。
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //追加 config.Routes.MapHttpRoute( name: "GetHogeHoge", routeTemplate: "api/products/hogehoge", defaults: new { controller = "products", action = "GetHogeHoge" } ); //追加 config.Routes.MapHttpRoute( name: "GetHoge", routeTemplate: "api/products/hoge", defaults: new { controller = "products", action = "GetHoge" } ); //デフォルトのルーティング config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
アクション名を指定すれば、振り分けは可能ですが、
やりすぎてしまうと、恐らく RESTFul から離れてしまうのではないかなと思います。
まとめ
WEB API のアクションメソッドのマッピングは、
以下のものが重要になります。
- HTTP メソッド
- ルーティングでのアクション名の指定
- パラメータ
先に挙げたオーバーロードっぽいものもあるため、
ちゃんとした RESTFul な設計でないと、簡単にマッピングが壊れてしまう気がします…。
壊れないようにするためには、テストを用意すればいいですが、
簡単に確認する方法があります。
ヘルプページ自動生成パッケージにて、表示されるAPI一覧には、
マッピングに失敗した API は表示されないようになっているので、お手軽に確認できます。