ASP.NET Web APIのコントローラーの戻り値型の使い分け
結論
以下の理由で、エラーレスポンスを返すときはIHttpActionResult型を使うのが良さそうです。
- 可読性がよい
- デバッグしやすい
- テストコードにstubが要らない
エラーレスポンスを返さないときは任意の型を使うのが良いです。
前提
ASP.NET Web APIのコントローラーの戻り値の型
次の4パターンがあります。
- 任意の型
- HttpResponseMessage
- void
- IHttpActionResult
IHttpActionResult は ASP.NET Web API 2 から増えました。
このうち
- HttpResponseMessageは、特に便利ではない
- voidは204レスポンス固定
ので、今回の議論からは外します。
エラーレスポンスのないAPI
GET /api/pruducts
のようなエラーレスポンスを返さないAPIを実装します。
任意の型
public IEnumerable<Product> Get()
{
return products;
}
メソッドシグネチャで戻り値の型が明示されていて良さげです。
IHttpActionResult
public IHttpActionResult Get()
{
return Ok(products);
}
- 戻り値型が固定の
IHttpActionResult
Ok(product)
が、ちょっと格好わるいです。
エラーレスポンスのないAPIは任意の型を使うのが良さそうです。
エラーレスポンスのあるAPI
GET /api/pruducts/:id
のようなエラーレスポンスを返すAPIを実装します。
任意の型
可読性
200 OK
public Product Get(int id)
{
return products.FirstOrDefault(p => p.Id == id);
}
ここまではエラーレスポンスのないAPIと一緒です。
404などのエラーレスポンスを返す時はどうするのでしょうか?Product
型以外はreturnできません。
Product
型をHttpResponseMessage
のサブクラスにしてレスポンスコードを持たせるのは、面倒です。
404 Not Found
public Product Get(int id)
{
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return product;
}
HttpResponseException
をthrowします。
例外であれば、メソッドの戻り値と違う型をthrowできます。
よくない点
ここで二つの疑問があります。
- 例外を作るソースコード
new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound))
がやたら長い - 制御フローに例外を使う
1番目はヘルパーメソッドを書けば解決できそうです。
2番目は例外的状態にだけ例外を使用する - Strategic Choiceによると
パフォーマンスが悪くなる。
可読性が低くなる。
関係ない例外を消費して、他のバグを見逃す危険がある。
の点があげられています。
パフォーマンスはチューニングの問題なので、ここでは考えません。
可読性が悪くてバグを見逃す可能性が高い点を考えると
こうすれば・・・
public Product Get(int id)
{
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
_404();
}
return product;
}
private void _404()
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
可読性はクリアできそうです。
デバッグ
ところで、デバッグしてみましょう。
ハンドルしていない例外を投げると、デバッガはそこで毎回止まります。
不便です。
テスト
controllerのテストを書いてみます。
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace HelloWorldAPI.Controllers.Tests
{
[TestClass()]
public class ProductsControllerTests
{
[TestMethod()]
public void GetTest()
{
new ProductsController().Get(2);
}
}
}
例外が発生します。
よく見るとArgumentNullException
です。Request
プロパティの値がnull
なので、起きる例外です。
Request
プロパティに何かしらのstubを設定する必要があります。
IHttpActionResult
可読性
404 Not Found
public IHttpActionResult Get(int id)
{
var product = products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
最初から読みやすいです。
ヘルパーメソッド
- Ok
- NotFound
はApiControllerに定義されたヘルパーメソッドです。
ApiController メソッド (System.Web.Http)に他のメソッド定義があります。
デバッグ
もちろん、デバッガで意図せずに止まりません。
テスト
先ほどのテストコードがそのまま動きます。
まとめ
-
GET /api/pruducts
のようなエラーレスポンスを返さないAPIは任意の型を使うのが簡単
-
GET /api/pruducts/:id
のようなエラーレスポンスを返すAPIはIHttpActionResult
を使うのが便利
参考
GET /api/pruducts
のようなエラーレスポンスを返さないAPIは任意の型を使うのが簡単GET /api/pruducts/:id
のようなエラーレスポンスを返すAPIはIHttpActionResult
を使うのが便利Author And Source
この問題について(ASP.NET Web APIのコントローラーの戻り値型の使い分け), 我々は、より多くの情報をここで見つけました https://qiita.com/ledsun/items/9bf486635aa5d3d45e6c著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .