如何在RESTful服务设计中正确支持记录的部分创建?

如何在RESTful服务设计中正确支持记录的部分创建?,rest,restapi,Rest,Restapi,我正在设计一个restful服务来支持一个现有的向导,该向导允许用户提交一个新的资源(我们称之为customer),但它是分块提交的 此向导在用户提交每个页面时对其进行验证,但仅对用户提交的页面进行验证。只有当用户选择提交客户进行最终处理时,它才会对整个对象进行完全验证 为了简化向导,并允许我们在添加更多字段时在维护版本中随意移动UI,我们没有将向导的结构编码到资源中。客户不会按照向导显示数据的方式“汇总” 设计RESTful服务时,资源的命名子文档不一定在该资源的完整文档中按层次显示(或者至少

我正在设计一个restful服务来支持一个现有的向导,该向导允许用户提交一个新的资源(我们称之为
customer
),但它是分块提交的

此向导在用户提交每个页面时对其进行验证,但仅对用户提交的页面进行验证。只有当用户选择提交客户进行最终处理时,它才会对整个对象进行完全验证

为了简化向导,并允许我们在添加更多字段时在维护版本中随意移动UI,我们没有将向导的结构编码到资源中。客户不会按照向导显示数据的方式“汇总”

设计RESTful服务时,资源的命名子文档不一定在该资源的完整文档中按层次显示(或者至少不以相同的方式显示),这是否奇怪

假设我的向导页面是:

  • 联系方式
  • 食物偏好
  • 恐惧清单
下面是一个示例客户对象:

// Note that the wizard page groupings don't show up explicitly
{
    customer: {
        firstName: "Pilsner",
        lastName: "Dopplebock",
        emailAddress: "nextguest@hotelcalifornia.com",
        addressLine1: "123 Fleece Place",
        addressLine2: ""
        town: "Ibinjad",
        region: "North Dakota",
        postalCode: "12123",
        homePhoneNumber: "2123234124",
        faxPhoneNumber: null,
        meatPreference: "well-done",
        allergies: "shellfish",
        fears: [
            "banshees",
            "baths",
            "sleeveless shirts"
        ]
    }
}
假设资源的基本URL为:

http://www.somewhere.com/customers
http://www.somewhere.com/customers/{id}
创建以下restful URL/方法是奇怪的还是错误的,即使
customer
实际上并没有按照它们所暗示的方式进行细分

http://www.somewhere.com/customers/contactinformation (POST)
http://www.somewhere.com/customers/{id}/contactinformation (POST, or PUT for update? maybe GET)
http://www.somewhere.com/customers/{id}/foodpreference (POST, or PUT for update?, maybe GET)
http://www.somewhere.com/customers/{id}/fears (POST to add a single item?, maybe PUT for a batch?, maybe GET)
我曾考虑过,如果我一次没有完整的资源,可以使用另一个向导URL,但在我看来,这似乎不适合资源导向:

http://www.somewhere.com/customerwizard/submitcontactinformation (POST)
http://www.somewhere.com/customerwizard/{customer-id}/submitcontactinformation
http://www.somewhere.com/customerwizard/{customer-id}/submitfoodpreference
http://www.somewhere.com/customerwizard/{customer-id}/fears
(可能是第二个问题,尽管相关):对于不一定显示在主集合上的集合样式资源,有一个
count
子属性是否奇怪?我想这样做是为了支持分页视图

http://www.somewhere.com/customers/count (GET)

我不认为这个问题是引用的问题的重复。您并不是要求对现有资源执行部分更新,而是要求服务器验证“部分”资源(我认为这些资源本身就是整个资源,而不是您稍后通常向用户展示的资源)

在这种情况下,REST不一定是正确的选择。REST旨在优化静态或半静态资源的读访问,这些资源由潜在的分布式受众多次访问。为了提供帮助,您能否回答以下问题:

  • 您是否希望在初始请求-响应通信完成后获得验证结果
  • 您是否曾经两次提交相同的数据(来自不同用户或来自同一用户)
  • 如果是,响应是否总是相同的,即验证算法是否具有确定性
  • 是否可以将所有这些未加密且清晰可见的数据发送给其他人
  • 如果你对所有这些回答都是肯定的,那么休息就是一个很好的选择。如果你对这三个问题的答案都是否定的,那么休息是不合适的。混杂的答案在一定程度上影响了决策

    如果我处在您的位置,并且没有进一步的数据,我将首先将其实现为HTTPS上的RPC接口,直到我了解了数据缓存和安全需求,这样我就知道系统的哪些部分将受益于缓存(仅在最终用户的机器上,或作为未加密的公共资源传输,并可由中介进行缓存


    有一个很棒的资源,它可能有助于确定REST是否真的是您希望在API设计中遵循的路径选择替代设计是一种权衡。根据每种设计各自的优点和缺点做出明智的决定。

    URL就像
    /customers/{id}/contactinformation
    等等并不奇怪。您可能想问自己的一个问题是,在写入时将客户实体拆分为单独的片段是否有意义,并不意味着它们在读取时可以更好地单独提供服务。这肯定会使任何HTTP缓存更合理。例如,如果要获取实体片段,然后获取父实体,后续对片段的PUT只会使片段无效,父实体随后可能会提供过时的数据。更简单的方法是获取较小的父实体(它具有指向每个实体片段的链接)然后获取每个片段,在这种情况下,对片段的放置会正确地提示后续的GET检索新的副本。

    与Nicholas Shanks相比,我认为类似向导的系统符合REST背后的思想。在Web上看到这样的交互概念并不少见,也就是说,通常应用于签出页面上e页面输入客户信息,下一页输入送货地址,第三页输入付款数据,然后是确认页面,确认页面将触发实际订单

    Jim Webber指出,在REST体系结构中,您主要实现一个域应用程序协议(如果您愿意,客户机将通过一个状态机)当客户端通过链接或类似于HTML表单的表单表示方式获得服务器提供的所有信息时,他们会跟进

    因此,REST体系结构中的上述结帐系统可能如下所示:将项目放入购物篮后,服务器会向您提供附加链接,这些链接用一些链接关系(伪HAL表示)进行注释:

    {
    ...,
    “_链接”:{
    “自我”:{
    “href”:”https://..."
    },
    “创建表单”:{
    “href”:”https://shop.acme.com/checkout-wizard-p1"
    },
    "https://acme.com/rel/checkout": {
    “href”:”https://shop.acme.com/checkout-wizard-p1"
    },
    ...
    }
    }
    
    URI本身与此无关,因为URI的拼写在REST体系结构中并不重要,只要它符合中概述的规则即可。它也可能以UUID而不是
    checkout wiza结束