http://api.twitter.com/1/statuses/home_timeline.xml
みたいなやつです。xml を json に変えると json になります。
元々はたけはらさんの Jsonable 属性を見て思ったんですけど、ルーティングを定義して昔作った XmlResult を使ったらいい感じになりました。
とりあえずさっくりとルーティングを定義します。
routes.MapRoute( "API", "api/{action}.{format}", new { controller = "api" } );
非常に簡単ですね。ぶっちゃけ説明要らないレベルですけど、これで
/api/product.xml
というような URL にマッチするようになります。
そしてコントローラを作ります。
public class ApiController : Controller { [OutputFormat] public ActionResult Product() { var model = new Product { Id = 10, Name = "かなり凄い商品", Price = 1980, Count = 10, }; return View(model); } }
普通に View メソッドを読んで ViewResult を返しています。OutputFormat という属性が付いていますが、これが今回のキモです。
それでは OutputFormat 属性のソースコードをぺたり。
public class OutputFormatAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { var viewResult = filterContext.Result as ViewResult; switch (filterContext.RouteData.GetRequiredString("format")) { case "json": filterContext.Result = new JsonResult { Data = viewResult.Model, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; break; case "xml": filterContext.Result = new XmlResult { Data = viewResult.Model }; break; } base.OnActionExecuted(filterContext); } }
やっていることは Jsonable 属性とほぼ一緒で、今回の奴はルートデータからフォーマットを引っ張ってきているだけです。XmlResult は JsonValueProviderFactory と JsonResult の XML 版を作ってみた - しばやん雑記 にあります。
/api/product.xml にアクセスした場合には以下のような XML が返ってきます。
<?xml version="1.0" encoding="utf-8"?> <Product xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Id>10</Id> <Name>かなり凄い商品</Name> <Price>1980</Price> <Count>10</Count> </Product>
/api/product.json にアクセスした場合には以下のような JSON が返ってきます。
{"Id":10,"Name":"かなり凄い商品","Price":1980,"Count":10}
ルーティングが柔軟だからこそ出来る芸当という感じですね。