【问题标题】:How to Submit Deeply Nested Resource using Restful APIs (HATEOAS)如何使用 Restful API (HATEOAS) 提交深度嵌套资源
【发布时间】:2013-07-15 14:14:48
【问题描述】:

假设我有一个应用程序资源,其中包含联系方式资源,联系方式包含地址资源。

例如。

Application
--> Name
--> Application Amount
--> Application Contacts 
--> --> Contact 1
--> --> --> Address
--> --> Contact 2
--> --> --> Address

在对应用程序进行 POST 时,我正在创建根应用程序。 对于应用程序联系人等所有子资源,我会进行 POST 以创建联系人 1 等...

我的问题是,Application = 提交某处进行处理,但我不想在填写所有内容之前提交它,也就是所有子资源。

So the order of submission
1) Create Application Resource --> POST /Application --> Get ID
2) Create Contact 1 Resource --> POST /Application/id/Contacts --> Get ID
3) Create Contact 1 Address Resource --> POST /Application/id/Contacts/id/Addresses
4) Create Contact 2 Resource --> POST /Application/id/Contacts --> Get ID 
5) Create Contact 2 Address Resource --> POST /Application/id/Contacts/id/Addresses
6) DECIDE TO SUBMIT HERE <--- ?? HOW?

乔什

【问题讨论】:

  • 从您的主要提交方法中,您应该像上面列出的那样单独调用每个帖子,更多的是模板类型的模式,这样您就可以控制。因此,请单独拨打电话,一旦所有孩子都接听电话,请拨打主要电话。也许您还可以考虑一次性返回所有需要的数据并在客户端上构建数据结构?将节省跨线数据传输。
  • 我假设您希望异步发出所有这些发布请求,然后在它们全部返回时将所有内容重新加入到一个线程中?或者您可以同步拨打电话吗?另外,由于您的标签,我假设您正在使用 C# 发出这些帖子请求?哪个 .NET 框架?

标签: c# web-services api rest hateoas


【解决方案1】:

您的设计不是 RESTful。您的资源可能与您的业务实体是一对一的映射?我不建议这样做,因为它会将您的域模型的内容暴露给外部世界,这可能会导致版本控制问题。它也使这样的问题变得比他们需要的更难 - 尽管您可能正在使用强制您进行这种设计的 REST 框架:-( .

要记住的是,REST 中的资源是您希望外部世界看到的域模型元素的抽象表示,它们很可能需要映射和转换才能转换为域对象。它们可以任意复杂。

我想说,这里的解决方案是让 POST 创建应用程序也创建联系人及其地址。然后,客户端可以提供现有联系人和地址的 URL(服务器可以取消对域对象的引用),或者在 single POST 中创建新的必要细节。然后以事务方式创建和关联实体的责任落在服务器身上。它只是返回对标识新应用程序的 URL 的引用。如果您需要知道联系人的 URL,那么您重新获取应用程序,它将包含它们。

假设您的资源是 JSON mime 类型,初始 POST 可能如下所示:

{
    Name: "Application name",
    Amount: "123.00",
    Contacts: [
        {
            Name: "Contact name",
            Address: {
                HouseNumber: "45",
                StreetName : "Sesame Street"
            }
        }
    ]
}
Return: {href:  “/Application/6789”}

到 /Application/6789 的 GET 将返回如下内容:

{
    Name: "Application name",
    Amount: "123.00",
    Contacts: [
        { mimeType: "application/vnd.com.myStuff.contact+json", href: "/Contact/203" }
    ]
}

【讨论】:

  • 像这样更粗粒度的方法还具有简化事务边界的额外好处
【解决方案2】:

您很可能会有某种状态字段来指示申请是否已提交。在这种情况下,我会建议以下两种方法:

1) 发布到应用程序资源,并将其状态字段设置为适当的值以表明您的意图:

POST /application/654321
status=submitted...

这是来自Fielding Dissertation的引用:

"REST 组件通过使用 表示以捕获其当前或预期状态 资源并在组件之间传输该表示。”

2) 将应用程序发布到特定集合 /submittedapplications,您也可以使用它通过 GET 搜索您提交的应用程序:

POST /submittedapplications
id=654321...

由于除了更新应用程序资源之外很可能还有其他处理步骤,因此您应该使用 POST 动词来指示重复提交是不可行的。

顺便说一句,这两种方法并不相互排斥,您当然可以在同一个 API 中实现这两种方法。

【讨论】:

    【解决方案3】:

    希望我正确理解了您的问题。如果我错过了重点,请告诉我,并且随时可以回来提供新内容。

    因此,如果所有“子资源”都已从第 1 步到第 5 步创建。在每个步骤中,都应该有一个返回的ID来确认资源创建成功。喜欢,

    POST /Application
    Return: {appid:  “/Application/id”}
    

    因此,只要第 5 步 POST 返回,就会创建最后一个资源。然后下一步是开始应用程序“处理”。

    “应用处理”可以看作是一种资源,业务行为是:“创建处理”资源和“检查处理结果”

    它们可以分别在“处理”资源上使用 POST 和 GET 进行建模。

    创建处理资源

    POST /Application/id/Processing
    Return:  {processingid: “/Application/id/Processing/id”}
    

    检查处理资源

    GET /Application/id/Processing/id
    Return: {processingid: “/Application/id/Processing/id”, <other info>}
    

    要恢复整个应用程序,

    GET /Application/id
    Return: {all info on the application including processing status as well…}
    

    希望对您有所帮助。

    【讨论】:

    • 处理更多的是应用程序的状态,而不是应用程序的资源。像上面的@dmibor 那样做并且将应用程序的状态设置为将开始处理并更新资源(技术上使用PUT)或将应用程序包装在其他东西中并创建新资源会更正确处理请求。像 POST /Request { ApplicationId:???或者甚至颠倒资源创建的顺序,首先创建所有联系人,然后在创建应用程序后立即开始处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多