如何构建一个 REST API,该 API 采用资源 id 的数组

Posted

技术标签:

【中文标题】如何构建一个 REST API,该 API 采用资源 id 的数组【英文标题】:How to construct a REST API that takes an array of id's for the resources 【发布时间】:2011-05-31 07:00:32 【问题描述】:

我正在为我的项目构建一个 REST API。获取给定用户 INFO 的 API 是:

api.com/users/[USER-ID]

我还想允许客户端传入用户 ID 列表。如何构建 API 以使其成为 RESTful 并接受用户 ID 列表?

【问题讨论】:

@Shuja 给出了最通用的答案,因为邮递员的其他答案不起作用并且依赖于数据库后端。但是,您可以有一个 API 端点来请求多个 ID。 【参考方案1】:

如果您在 URL 上传递所有参数,那么逗号分隔的值可能是最佳选择。然后你会得到一个如下的 URL 模板:

api.com/users?id=id1,id2,id3,id4,id5

【讨论】:

@uclajatt,REST 是一种架构模型,而不是一种协议,如果您研究当今可用的主要 REST API,您会发现有多种实现方式。我建议的方法可能是最接近该概念的方法之一,因为它完成了此处描述的所有约束:en.wikipedia.org/wiki/…。您只能使用 CSV 来表示请求中的数组,而服务响应应使用 XML 或 JSON 进行序列化。有什么特别的原因让您不认为我的方法是 REST? 为什么不这样呢? api.com/users?id=id1&id=id2&id=id3&id=id4&id=id5 @senfo,我更喜欢 id=id1,id2,id3 因为它使 URI 更短且更易于阅读(例如在调试操作期间由人类阅读)。如果 id 之间还有其他参数,则每个值的单独参数会使 URI 更难遵循:api.com/users?id=id1&id=id2&joined-after=2013-01-01&id=id3 但是,大多数 Web 服务器支持的 URL 长度约为 2,000 字节。如何让我的 API 支持多达 5,000 个 id? @senfo 在…?id=1&id=2&id=3、there is no guarantee 等 URL 中,重复的查询参数将组合成一个数组。使用上面的查询字符串,php 恰好告诉您 id 等于 [1, 2, 3],但 Ruby on Rails 告诉您它等于 3,其他框架也可能有不同的行为,例如说id 等于1。像 …?id=1,2,3 这样的 URL 避免了这种混淆的可能性。【参考方案2】:

您可以使用 ASP.NET MVC 构建 Rest API 或 restful 项目,并将数据作为 JSON 返回。 一个示例控制器函数是:

        public JsonpResult GetUsers(string userIds)
        
           var values = JsonConvert.DeserializeObject<List<int>>(userIds);

            var users = _userRepository.GetAllUsersByIds(userIds);

            var collection = users.Select(user => new  id = user.Id, fullname = user.FirstName +" "+ user.LastName );
            var result = new  users = collection ;

            return this.Jsonp(result);
        
        public IQueryable<User> GetAllUsersByIds(List<int> ids)
        
            return _db.Users.Where(c=> ids.Contains(c.Id));
        

然后您只需通过提供 Ids 数组的常规 AJAX 函数调用 GetUsers 函数(在这种情况下,我使用 jQuery stringify 将数组作为字符串发送并在控制器中将其取消实现,但您可以只发送数组int 并将其作为控制器中的 int 数组接收)。我使用 ASP.NET MVC 构建了一个完整的 Restful API,它将数据作为跨域 json 返回,并且可以从任何应用程序中使用。当然,如果您可以使用 ASP.NET MVC。

function GetUsers()
    
           var link = '<%= ResolveUrl("~")%>users?callback=?';
           var userIds = [];
            $('#multiselect :selected').each(function (i, selected) 
                userIds[i] = $(selected).val();
            );

            $.ajax(
                url: link,
                traditional: true,
                data:  'userIds': JSON.stringify(userIds) ,
                dataType: "jsonp",
                jsonpCallback: "refreshUsers"
            );
    

【讨论】:

抱歉,我没有询问如何实现 API。我只是在询问如何构造 API URI,以便客户端可以访问有关一组用户的信息。我可以通过查询参数传递 id,但我相信这不会很安静。 @uclajatt 为什么你认为这不是 RESTful? 我相信通过查询参数传递 id 或任何其他值确实是一种与系统交互的宁静方法。你如何构建你的 Uri 这取决于你。作为用户/全部、用户/数组、数组/用户或您认为有意义的任何其他命名约定。考虑到 MVC 框架是如何工作的,它很容易用于构建一个 RESTful API,因为您可以根据需要组织和构建 Uris。一旦有了 Uris,您就可以使用 AJAX 作为一个字符串传递参数,或者如果您正在使用表单并发布到 MVC 操作,则作为多个值。 @uclajatt 现在已经两次在这篇文章中被问到为什么您认为在查询参数中传递逗号分隔列表不是 RESTful 并且您甚至懒得回答它,更不用说接受了这些非常合理的解决方案中的任何一个!?!不酷。【参考方案3】:

我找到了另一种使用@PathParam 来做同样事情的方法。这是代码示例。

@GET
@Path("data/xml/Ids")
@Produces("application/xml")
public Object getData(@PathParam("zrssIds") String Ids)

  System.out.println("zrssIds = " + Ids);
  //Here you need to use String tokenizer to make the array from the string.

使用以下网址调用服务。

http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76

在哪里

http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76

【讨论】:

我喜欢这个,因为 GET 是一致的。在此示例中,您可以使用一个或多个数字。这并不是真正的搜索(参数),因为您正在为后端提供您想要的确切 ID。 我看到最受好评的答案不起作用,您的答案可能是最通用的答案。应该被接受为答案。【参考方案4】:

尽管我更喜欢这种方法:-

    api.com/users?id=id1,id2,id3,id4,id5

正确的做法是

    api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

    api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5

rack 就是这样做的。 php 就是这样做的。这也是node的做法......

【讨论】:

我不确定将 PHP 标准作为遵循指南是否是最好的建议。 eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design 这不是 Flask 的做法。【参考方案5】:
 api.com/users?id=id1,id2,id3,id4,id5
 api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5

IMO,上面的调用看起来不像 RESTful,但是这些是快速有效的解决方法 (y)。但是 URL 的长度受网络服务器的限制,例如tomcat。

RESTful 尝试:

POST http://example.com/api/batchtask

   [
    
      method : "GET",
      headers : [..],
      url : "/users/id1"
    ,
    
      method : "GET",
      headers : [..],
      url : "/users/id2"
    
   ]

服务器将回复新创建的 batchtask 资源的 URI。

201 Created
Location: "http://example.com/api/batchtask/1254"

现在客户端可以通过轮询来获取批量响应或任务进度

GET http://example.com/api/batchtask/1254


这是其他人尝试解决此问题的方法:

Google Drive Facebook Microsoft Subbu Allamaraju

【讨论】:

get 多个结果的 POST 请求不是 RESTful。您的示例显示了创建一个适合 POST 的资源,但这与原始问题完全不同 创建临时资源是 RESTful 的,不是吗?我正在使用 GET 获取资源,它又是 RESTful。 是的,但这些都不是在原始问题中,它只是询问获取多个用户 ID 的信息 感谢@Anentropic 指出。我再次阅读了这个问题,它询问 如何构建一个 REST API 来获取资源的 id 数组? 我同意,我的答案是不同的。很抱歉没有明白你的意思。 这可能违反了 Cacheability REST 原则。缓存此类请求很困难。如果我们缓存对此类批处理请求的响应,那么无效化是很困难的。【参考方案6】:

似乎有几种方法可以实现这一点。我想提供我的解决方法:

GET /users/<id>[,id,...]

由于 URI 长度限制,它确实限制了可以指定的 id 数量 - 我发现这是避免滥用端点的好方法。

我更喜欢对 ID 使用路径参数,并将查询字符串参数保留给过滤器。它通过确保在 URI 处响应的文档仍然可以被视为资源并且仍然可以缓存可以来保持 RESTful-ness(尽管有一些箍可以跳转到有效地缓存它)。

我对 cme​​ts 很感兴趣,因为我正在寻找这种形式的理想解决方案 :)

【讨论】:

以上是关于如何构建一个 REST API,该 API 采用资源 id 的数组的主要内容,如果未能解决你的问题,请参考以下文章

VSTS:如何使用 REST API 获取由构建触发的发布 ID

构建一个测试,该测试使用在 localhost 上运行的基于 Spring 的 REST API URL 进行测试

REST API - 如何构建端点 url

如何快速构建基于Spring4.0的Rest API

如何使用 Azure DevOps REST Api 编写构建计划脚本?

Django - 使用从类似 REST 的 API 检索的数据构建报告的应用程序