2013-05-30 37 views
4

我已经使用Web API编写了REST服务,并且在阅读Brian Mulloy提供的Web API Design部分后,试图弄清楚如何实现与Web API的关联。具有关联的REST风格的Web API。可能吗?

的Web API设计精华:

协会

资源几乎总是有其他 资源的关系。在 aWebAPI中表达这些关系的简单方法是什么?

让我们再看看我们在名词中建模的API是否好, 动词是坏的 - 与我们的狗资源交互的API。 请记住,我们有两个基地网址:/狗和狗/ 1234。

我们使用HTTP 动词来操作资源和集合。我们的狗属于 业主。要获得所有属于特定主人的狗,或者 创建一个新的狗对于主人,做一个GET或POST:

GET /老板/ 5678 /狗
POST /老板/ 5678 /狗

现在,关系可以是 复杂。业主与兽医有关系,兽医与狗有关系,与食物有关系,等等。 看到人们将这些字符串串起来形成一个URL 5 或6级深度并不罕见。请记住,一旦你拥有一个 级别的主键,通常不需要包含上面的级别,因为 已经有了你的特定对象。换句话说,你不应该在 需要太多的情况下,URL比我们上面的 /resource/identifier/resource更深。

于是,我就添加一个控制器方法,为联想类似如下:

public class EventsController : ApiController 
{ 
    // GET api/events 
    public IEnumerable<Event> Get() 
    { 
     // get list code 
    } 

    // GET api/events/5 
    public Event Get(int id) 
    { 
     // get code 
    } 

    // POST api/events 
    public void Post([FromBody]Event evnt) 
    { 
     // add code 
    } 

    // POST api/events/5 
    public void Post(int id, [FromBody]Event evnt) 
    { 
     // update code 
    } 

    // DELETE api/events/5 
    public void Delete(int id) 
    { 
     // delete code 
    } 

    // GET api/events/5/guests 
    public IEnumerable<Guest> Guests(int id) 
    { 
     // association code 
    } 
} 

我也修改了我的路线模板以下几点:

config.Routes.MapHttpRoute("ApiWithAssociations", 
          "api/{controller}/{id}/{action}"); 
config.Routes.MapHttpRoute("DefaultApi", 
          "api/{controller}/{id}", 
          new { id = RouteParameter.Optional }); 

不幸的是,当我做的事件资源的更新/发布现在,我得到一个HTTP 500内部服务器错误,其中包含响应正文

多的行动中发现匹配

我试着与添加System.Web.Http.HttpPostAttribute(和其他HTTP动词)结合很好,但无济于事修改路由模板的请求。

有没有人试过这个,并得到它的工作?任何帮助,将不胜感激。如果绝对不可能有一个http动词的倍数,那么我想我必须放弃与我的REST服务的关联。

编辑:解

使用拉迪姆·克勒的回答,我能得到这个工作。在HttpGetAttribute添加到来宾方法,像这样:

// GET api/event/5/guests 
[HttpGet] 
public IEnumerable<Guest> Guests(int id) 
{ 
    // association code 
} 

,并增加了另外的路线,以满足默认的GET动作像如下:

config.Routes.MapHttpRoute("DefaultGet", 
          "api/{controller}/{id}", 
          new {action = "Get"}, 
          new {httpMethod = new HttpMethodConstraint(HttpMethod.Get)}); 
config.Routes.MapHttpRoute("ApiWithAssociations", 
          "api/{controller}/{id}/{action}"); 
config.Routes.MapHttpRoute("DefaultApi", 
          "api/{controller}/{id}", 
          new {id = RouteParameter.Optional}); 

回答

2

的解决方案,可能是一个明确的POST映射

只需添加新的定义,这将用于事件/ 5 POST

// explicit Post() mapping 
config.Routes.MapHttpRoute(
    name: "DefaultPost", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { action = "Post" } 
    , constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) } 
    ); 

// existing 
config.Routes.MapHttpRoute("ApiWithAssociations", 
    "api/{controller}/{id}/{action}"); 
config.Routes.MapHttpRoute("DefaultApi", 
    "api/{controller}/{id}", 
    new { id = RouteParameter.Optional }); 
+0

不幸的是,使用[HttpGet]装饰Guests方法会使url api/events/5 GET请求路由到此Guest方法,这不是所需的功能。 –

+0

我更新了我的答案。这能解决问题吗?因为,它保持原样,但教导API使用POST方法将事件/ 5用于POST。没有更多的客人HttpGet属性 –

+0

实际上,该解决方案给我的错误“所请求的资源不支持HTTP方法'GET'”当我使用GET api/events/5/guests。使用你的想法,我会更新我的问题,包括工作解决方案。 –

1
+0

我居然使用自定义ActionSelector感谢创造了一个有效的解决方案您链接的博客帖子,但是在最小化定制代码的努力中,我决定使用Radim的解决方案。 –