带关联的RESTful Web API。可能吗?

时间:2013-05-30 15:10:54

标签: rest asp.net-web-api asp.net-web-api-routing

我使用Web API编写了一个REST服务,在阅读了Brian Mulloy的这个Web API Design部分之后,我试图弄清楚如何实现与Web API的关联。

Web API设计摘录:

  

关联

     

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

     

让我们再看一下我们在名词中建模的API是好的,   动词是坏的-theAPI与我们的狗资源相互作用。   请记住,我们有两个基本URL:/ dogs和dogs / 1234。

     

我们正在使用HTTP   用于操作资源和集合的动词。我们的狗属于   拥有者。让所有的狗属于特定的所有者,或   为该主人创建一条新狗,进行GET或POST:

     

GET / owner / 5678 / dogs
  POST / owner / 5678 / dogs

     

现在,关系可以   复杂。业主与兽医有关系   与狗有关系,与食物有关系,等等。   看到人们将这些字符串组合在一起制作URL 5并不罕见   或6级深。请记住,一旦拥有主键   级别,您通常不需要包含上述级别,因为   你已经有了特定的对象。换句话说,你不应该   需要太多的情况,其中URL比我们上面的更深   /资源/标识符/资源。

所以我尝试为关联添加一个控制器方法,如下所示:

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服务的关联。

编辑:解决方案

使用RadimKöhler的回答,我能够使这个工作。将HttpGetAttribute添加到Guests方法,如下所示:

// 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 个答案:

答案 0 :(得分:2)

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

只需添加新定义,该定义将用于events / 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 });

答案 1 :(得分:1)