REST - 处理子资源访问

时间:2014-01-06 19:57:51

标签: rest design-patterns restful-url

我正在评估可能的REST API设计,并希望询问有关处理嵌套资源的方法的反馈或最佳实践。

考虑以下(JSON表达的)人工书库的数据模型,类似于我正在查看的数据。请忽略这样一个事实:没有图书馆等书就可以存在。

{ "library-name" : "foobar",
  "rows" : 
[
  {"row-id":"1", 
   "shelves": 
      [
        {"shelf-id":"1", 
            "books": 
              [
                {
                  "book":
                    {"book-name":"abc", "author":"someone"}
                }
              ]
         }
       ]
    }
 ]
}

假设可能的REST API设计是:

/library (the root API URI)
/library/{library-name}/
/library/{library-name}/{row-id}
/library/{library-name}/{row-id}/{shelf-id}
/library/{library-name}/{row-id}/{shelf-id}/{book-name}

对于POST操作,服务器将实现允许的功能:

  • 添加新书,直接执行POST到/ library / {library-name},将书的所有细节编码到嵌套数据结构内的架子,行等(如图所示)。
  • 每个资源级别都允许GET操作。 GET将返回完全嵌套的数据(例如,返回作为JSON数据的所有行/架子和给定库的书籍等)。

上面有一些权衡:

  • 可以通过多个URI访问给定的图书资源。例如,对/ library / {library-name}的POST可以创建一本书,对于/ library / {library-name} / {row-id} / {shelf-id}的POST也是如此。在这种间接POST情况下,数据而不是URI标识实际的目标子资源。这是RESTfuL吗?
  • 允许在POST / PUT操作中通过父资源处理资源在批量操作中很有用;节省了往返次数。这种好处是以客户端和服务器必须处理的更复杂的数据结构和处理程序代码为代价的。

评论?我在这里缺少什么(我没有找到上面的很多例子,这让我觉得这不是一个常见的设计模式)?

1 个答案:

答案 0 :(得分:1)

根据您的描述,您打算将'row'和'shelf'作为URL的组成部分公开,如果这是您的设计意图,那就没问题了。这就是你问题的来源,因为如果'row'和& 'shelf'是资源URL的组成部分,那么你不应该进行'so-call'批量POST / PUT / DELETE操作,但只要书名是唯一的,GET就可以了。

我可以看到您有以下业务操作

A) - 在特定位置创建图书

HTTP POST /library/{lib-name}/{row-id}/{shelf-id}/{book-name}
Body: {json info for the book}

B) - 获取所有书籍

//in all library        
HTTP GET /library/

//in a specific library         
HTTP GET /library/{lib-name}/ 

//in a specific row         
HTTP GET /library/{lib-name}/{row-id}/

//in a specific row & shelf         
HTTP GET /library/{lib-name}/{row-id}/{shelf-id}/

C) - 获取特定书籍

HTTP GET /library/{lib-name}/{row-id}/{shelf-id}/{book-name}

//If the book-name or ID is unique, you can access it from the toplevel
HTTP GET /library/books/{ book-name}

如果排&架子不是URL的重要部分,你将有

A) - 创建一本书

HTTP POST /library/{lib-name}/{book-name}
Body: {json info for the book including row & shelf}

B) - 获取所有书籍

//-in all library       
HTTP GET /library/

//-in a specific library        
HTTP GET /library/{lib-name}/ 

C) - 获取特定书籍

//If the book-name or ID is unique, you can access it from the toplevel
HTTP GET /library/books/{ book-name}

更新

此处的决定是从应用程序的角度来看,{row} / {shelf}对于在URL中作为管理 REST资源的方式暴露给客户端至关重要,或者它们是只是一本书的属性

如果{row}& {shelf}也是 REST资源供客户端管理或用于标识资源的唯一路径(本例中是书),将它们作为URL的一部分是有意义的,它们应该受REST / HATEOAS约束。换句话说,您不应该使用复杂的主体来包含POST中的所有“子资源”。

GET更加微妙。

网址上的GET很简单

/library/{lib-name}/{row-id}/{shelf-id}/{book-name}

GET可以应用于'/ library / {lib-name} /'。在这种情况下,正文应该包含某种形式的结构化链接到下面的资源,如

[
{/library/{lib-name}/{row-id}/{shelf-id}/{book-name}}, 
{/library/{lib-name}/{row-id}/{shelf-id}/{book-name}},
 ...]

但如果它们只是属性,那么它们可能是复杂体的一部分,因为它们不会从可寻址性,链接和连接性的视图中添加任何值。

REST关注以下内容(从RESTful Web Services复制)

  • 寻址
  • 无国籍
  • 表示法
  • 链接和连接
  • 统一界面

关于REST的两本好书,并就你感兴趣的主题进行了一些讨论。