第3回 APIコントローラの実装方法:連載:ASP.NET Web API 入門(3/3 ページ)
RESTfulなWeb APIを実装してみよう。ASP.NET Web API 2を使えば、実践的なHTTPサービスが容易に実装できる点に注目してほしい。
2-4 HTTPレスポンスの内容を指定する
HTTPレスポンスの内容は、アクション・メソッドの戻り値の型で表し、APIの処理を実行した後に戻り値のインスタンスを返すことで、HTTPレスポンスの内容を指定できる。
またもう1つの方法として、特定の例外クラスをスローすることでもHTTPレスポンスの内容を指定できる。アクション・メソッド内でHttpResponseExceptionクラス(System.Web.Http名前空間)のインスタンスをスローすることで可能になる(後述するが、このときに構築されるHTTPレスポンスの中身は、必ずしもエラーを表すものではないことと、通常の.NET Frameworkの例外とは扱いが異なるので注意)。
ASP.NET Web APIではこれら2つの方法を組み合わせることで、HTTPレスポンスの柔軟な操作が可能になる。HTTPレスポンスの指定方法と、実際に構築されるHTTPレスポンスの内容を下の表8、9にまとめた。
メソッドの戻り値の型 | 構築されるHTTPレスポンスの内容 |
---|---|
Void | ステータス・コード: 204 No Content |
void, HttpResponseMessage以外の型(独自クラスやプリミティブ型など) | ステータス・コード: 200 OK Body:戻り値の値を書式で変換した値が格納される |
HttpResponseMessage | HttpResponseMessageクラスのプロパティで表される |
・バージョン2では、「IHttpActionResult」クラスを戻り値に指定する方法が追加されている。
・非同期を利用する場合、戻り値の型にはTask<T>クラス(System.Threading.Tasks名前空間)も指定できる。この場合に構築されるHTTPレスポンスは、表のとおり、型パラメータ(Tに指定した型)に対応するものとなる。
メソッド内 | 構築されるHTTPレスポンスの内容 |
---|---|
HttpResponseExceptionをスローする | HttpResponseExceptionクラスのResponseプロパティ(HttpResponseMessage型)で表される |
表9 HTTPレスポンスを、例外をスローすることで表す場合 |
以降、サンプル・コードと共にそれぞれのHTTPレスポンスの指定方法と、どのようなときに利用できるかを解説していく。
○ 戻り値にvoidを指定する
下のコードのように、アクション・メソッドの戻り値にvoidを指定すると、ステータス・コード「201 No Content」がクライアントへ返される。
public void Delete()
{
}
データの更新や削除などの処理を行うAPIにて、処理は成功したが、クライアントへ返すべき情報がない場合に、voidを指定するとよいだろう。
○ 戻り値にvoid/HttpResponseMessage以外の型を指定する
この方法は、クライアントへ何らかのリソースを返したい場合に利用する。戻り値には、リソースを表す型を指定する。構築されるHTTPレスポンスは、ステータス・コードが「200 OK」、Bodyには戻り値を適切な書式(JSONやXMLなど)で変換された値が格納される**11。
*11Bodyへ格納するときに行われる変換の書式は、HTTPリクエストの内容(デフォルトでは、ヘッダ「Accept」の値)によって選択される。
リスト9と表10は、アクション・メソッドの戻り値に文字列型を指定した場合の例。リスト10と表11はPerson(独自クラス)データのコレクション型を指定した場合の例である。
public string GetName()
{
return "taro";
}
ステータス・コード | 200 OK |
---|---|
Body(JSON形式の場合) | "taro" |
表10 戻り値の型にString型を指定した場合に返されるHTTPレスポンスの例 |
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class PersonsController : ApiController
{
public IEnumerable<Person> Get()
{
var list = new List<Person>()
{
new Person() { Id = 1, Name = "taro" },
new Person() { Id = 2, Name = "hanako" }
};
return list;
}
}
ステータス・コード | 200 OK |
---|---|
Body(JSON形式の場合) | [{"Id":1,"Name":"taro"},{"Id":2,"Name":"hanako"}] |
表11 戻り値の型にIEnumerable<Person>を指定した場合に返されるHTTPレスポンスの例 |
都度、独自クラスを用意することが手間である場合は、JSON形式に限り、下のように匿名型を利用することもできる(XML形式に変換される場合、変換するコンポーネントが匿名型のシリアライズに対応していないため、エラーが発生するので注意)。
public object Get()
{
string[] members = new string[] {"taro", "hanako"};
return new { name = "groupA", members = members };
}
ステータス・コード | 200 OK |
---|---|
Body(JSON形式の場合) | {"name":"groupA","members":["taro","hanako"]} |
表12 戻り値を匿名型で指定した場合に返されるHTTPレスポンスの例 |
これらの方法は、例えばHTTPメソッド「GET」で何らかのリソースを返すAPIでよく利用される。任意の型を指定できるので、クライアントへ返したいリソースに合わせて、独自クラスや、String型、コレクション型など、さまざまな型を指定できることが利点だ。
○ 戻り値にHttpResponseMessageを指定する
この方法は、返したいHTTPレスポンスの内容を詳細に制御したい場合に利用する。HttpResponseMessageクラスの生成は、コンストラクタより生成することが可能だが、ApiControllerクラスのRequestプロパティから、拡張メソッド*12を利用して生成するとよいだろう。
*12System.Net.Http名前空間で定義されているHttpRequestMessageExtensionsメソッド。
以下のリストは、それぞれ各種ステータス・コードを指定して、HttpResponseMessage型の戻り値を返している例だ。このとき、リソースを組み合わせて返したり(リスト13)、ヘッダ情報を付け加えて返したり(リスト14)できる。
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
public HttpResponseMessage Get()
{
var person = new Person() { Name = "taro" };
return Request.CreateResponse(HttpStatusCode.OK, person);
}
public HttpResponseMessage Post()
{
var customer = new Customer();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, customer);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = customer.Id }));
return response;
}
○ HttpResponseExceptionをスローする
次は、戻り値の型ではなく、HttpResponseExceptionクラスのインスタンスをスローしてHTTPレスポンスの内容を指定する方法だ。
この方法は、APIの処理の途中で、正常に処理が終了した場合のHTTPレスポンスとは別の内容を返したいときに利用できる。例えば、顧客APIコントローラ・クラスでも記述されている以下のコードが事例の1つである。
public Customer GetCustomer(int id)
{
// Customersテーブルから、idが一致するデータを取得
Customer customer = db.Customers.Find(id);
if (customer == null)
{
// 一致するデータ存在しない場合は、ステータス・コード404を返す
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); // ……(1)
}
// Customerデータを返す
return customer;
}
(1)HttpResponseExceptionクラスのインスタンスをスローしている。
このリスト15に記述されているAPIの主な処理は、URLで指定されたIdと同じIdを持つ顧客データを返すことだ。だが、該当する顧客データが存在しない場合は、ステータス・コード「404 Not Found」を返すという処理も行う。
この場合、これまで解説した戻り値の型を指定する方法では、下のリスト16のように、戻り値の型にHttpResponseMessageを指定して、HTTPレスポンスの内容を指定するであろう。
public HttpResponseMessage /* ……(1) */ GetCustomer(int id)
{
// ……省略……
if (customer == null)
{
// 一致するデータ存在しない場合は、ステータスコード404を返す
return Request.CreateResponse(HttpStatusCode.NotFound); // ……(2)
}
// Customerデータを返す
return Request.CreateResponse(HttpStatusCode.OK, customer); // ……(2)
}
同じ振る舞いが定義されたAPIのコードであるリスト15とは違い、アクション・メソッドの戻り値の型にHttpResponseMessageクラスを指定し((1))、顧客データの存在の有無に関わらずHttpResponseMessageクラスのインスタンスを返している((2))。
もちろんこの方法でも正常に動作するが、この場合はコード15ように、HttpResponseExceptionオブジェクトをスローする方法を推奨する。なぜなら、戻り値の型にHttpResponseMessageクラスではなく、顧客データを表すCustomerクラスを指定することにより、処理が成功した場合は顧客データを返すことを表現し、データが存在しないといったように処理が成功しない場合は、成功時とは違うHTTPレスポンスを返す、ということを表現できるからだ。
このように戻り値の型でAPIの本来の目的を表現することは、人間の目だけではなくプログラムの目にとっても有効である。ヘルプ・ページの自動生成*13など、APIの定義をプログラムから読み取ることは少なくない。ぜひとも、このHttpResponseExceptionオブジェクトのスローを活用してほしい。
*13ASP.NET Web APIのヘルプ・ページについては、「ASP.NET MVCの新機能」を参考のこと。
説明が長くなってしまったが、HttpResponseExceptionオブジェクトをスローする利点を把握したところで、サンプル・コードと共に実装方法を確認しよう。
HttpResponseExceptionクラスは、以下のリストに示すように、コンストラクタからインスタンスを生成する。このときも、リソースを組み合わせて返したり(リスト17、リスト18)できる。
public string Get()
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
public string Get()
{
var person = new Person() { Name = " Taro" };
HttpResponseMessage reponse = Request.CreateResponse(HttpStatusCode.OK, person);
throw new HttpResponseException(reponse);
}
補足: HttpResponseExceptionクラスとそのほかのExceptionクラスについて
アクション・メソッド内にて、HttpResponseExceptionクラス以外の例外クラスがスローされた場合は、ASP.NET Web APIフレームワークによって、ステータス・コード「500 Internal Server Error」のHTTPレスポンスが返される。これは、例外処理を行う場合に利用する仕組みだ。同じ例外クラスでも、HttpResponseExceptionクラスとそのほかの例外クラスでは、挙動と目的が違うので注意してほしい。
APIコントローラの実装についての解説は以上になる。ASP.NET Web APIにおける最低限必要になる実装の詳細な紹介は、あと残すところ「ルーティングの設定」のみだ。
本稿では、ASP.NET Web APIの最低限必要となる実装の内の1つである「APIコントローラの実装」についての解説を行った。次回からは、「ルーティングの設定」と、ASP.NET Web APIの特徴を生かした実装について解説を行う予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.