【问题标题】:Web API - REST help and clarificationWeb API - REST 帮助和说明
【发布时间】:2015-02-28 07:10:25
【问题描述】:

我正在使用 WebAPI 编写一个 API,虽然我正在从头开始设计它,但我正在尝试使其成为 RESTful。过去在做 Web 服务工作时,我总是使用 RPC 模式(ASMX、SOAP 等)——例如。使用与我想要它做的匹配的任意方法名称。对我来说,这似乎比 REST 更直观、更明确,但鉴于 WebApi 本质上似乎更 RESTful(我知道您可以更改路由,所以它不是),我决定尝试使其成为 RESTful。

我了解(我认为!)基础知识 - 例如。 POST 用于创建,PUT 用于指定 ID 时更新,GET 用于获取,DELETE 用于删除等。

我的困惑是如何处理返回集合与单个对象。例如,假设我有一个名为 UsersController 的 API 控制器。据我所知,我有以下网址:

GET: /api/users (lists all users)
GET: /api/users/1 (lists details about user with ID 1)
POST: /api/users (creates a new user with details sent in the POST data)
PUT: /api/users/1 (updates the existing user with ID 1 with details sent in the POST data)
DELETE: /api/users/1 (deletes the existing user with ID 1)

对于上面的第一个 URL,我还需要发送各种过滤/搜索条件。这个标准是否只是作为查询字符串参数传递?或者我应该为这个“搜索”功能使用完全不同的控制器?例如。用户搜索控制器?如果是这样,在这种情况下应该是 POST 还是仍然是 GET?实际上,当我写这篇文章时,我想知道一个单独的控制器是否有意义,因为我可能希望在 GET 中为单个用户返回比在搜索结果中返回的更多详细信息。如果同一个控制器确实为单个对象 GET 和返回集合的 GET 返回不同的数据,是否会导致它不是 RESTful?

【问题讨论】:

    标签: c# web-services rest asp.net-web-api


    【解决方案1】:

    如果你想通过条件作为查询字符串参数传递给 URI,你可以使用属性路由到 WebApi 来做到这一点。我认为attribute-routing-in-web-api 对你有帮助。

    【讨论】:

      【解决方案2】:

      对于上面的第一个 URL,我还需要发送各种过滤/搜索条件。这个条件是否只是作为查询字符串参数传递?

      使用查询字符串来指定过滤器/搜索参数绝对是有意义的。

      我应该为这个“搜索”功能使用完全不同的控制器吗?例如。用户搜索控制器?

      你不应该那样做。我在这里看到了几个原因:

      1. GET: /api/users 中的功能几乎相同
      2. 您可以通过一种方法轻松实现GET: /api/usersGET: /api/users?filter=...&sort=...GET: /api/users/1

        //If you are using EF it could look like
        //filter and sort arguments could be added here as well
        public HttpResponseMessage Get(int? id)  
        {
           if(id.HasValue)
           {
               return Request.CreateResponse(
                   HttpStatusCode.OK, 
                   Context.Users.SingleOrDefault<Users>(u => u.Id == id));              
           }
        
           var users = Context.Users.Select(apply filter).OrderBy(apply sort).ToList();
           return Request.CreateResponse(HttpStatusCode.OK, users);   
        }
        

      您可以查看OData - 它可能对您的实施有所帮助。

      1. 在不同控制器之间传播此逻辑会损害单一职责原则 - 您的用户控制器应处理与用户相关的所有逻辑,并且仅处理此逻辑

      如果是这样,在这种情况下应该是 POST 还是仍然是 GET?

      如果你想让你的 API RESTful,你应该使用 GET。 但是您应该知道,通过 GET 返回 JSON 对象数组可能容易受到JSON hijacking 的攻击。此漏洞的最简单解决方案之一是允许仅通过 POST 获取 JSON 数组(还有其他解决方案)。

      我可能希望在 GET 中为单个用户返回比在搜索结果中返回的更多详细信息。如果同一个控制器确实为单个对象 GET 和返回集合的 GET 返回不同的数据,是否会导致它不是 RESTful?

      这完全可以为单个对象返回比集合更多的详细信息。它不会以任何方式影响您的 API 的 RESTful。

      评论

      你写的:

      指定 ID 时 PUT 进行更新

      其实也不完全正确:

      • 应该使用 PUT 来完全替换整个实体
      • 应使用 PATCH 执行部分更新。

      【讨论】:

      • 感谢您提供非常详细的回答。如果我确实有一个单独的搜索控制器,我想知道使用 POST 的原因是因为我将搜索本身视为一种资源,所以我假设因为我正在“创建搜索”,所以使用它仍然是 RESTful邮政。但也许这太过分了? ;) 我明白你的观点,尽管它通过不必要的分离来减少干燥。此外,关于 JSON 劫持的非常有趣的读物!感谢您的链接:)
      【解决方案3】:

      是的,我会将过滤器参数作为查询字符串选项传递。您的应用程序的“宁静”不依赖于控制器结构,因此您可以遵循最适合您的应用程序的结构

      【讨论】:

        猜你喜欢
        • 2014-08-08
        • 2012-08-01
        • 1970-01-01
        • 2013-11-19
        • 1970-01-01
        • 2011-04-22
        • 2014-12-27
        • 1970-01-01
        • 2013-07-08
        相关资源
        最近更新 更多