在ServiceStack中使用PATCH进行部分更新的推荐方法是什么?

时间:2013-08-21 07:09:02

标签: api servicestack

我正在使用ServiceStack框架构建RESTful API。我需要更新的很多资源非常庞大,每个类最多有40个属性,所以我想做部分更新而不是替换整个资源。通常客户端只需要更新40个中的一个或两个属性,所以我想发送一个由少数属性组成的JSON主体。

由于所有属性组合都是可能的,因此按照此处的建议为每个类创建一个“更新”类是不可行的:https://github.com/ServiceStack/ServiceStack/wiki/New-Api#patch-request-example

在Microsoft ASP.NET WebAPI OData包中,有一个Delta类,它接受类的子集并根据此子集(http://www.strathweb.com/2013/01/easy-asp-net-web-api-resource-updates-with-delta/)更新资源。这是我想要的功能,因为我将拥有相当多的类,所以通用方法最好。

基本上,如果我有一个班级

public class MyClass {
   public int a { get; set; }
   public int b { get; set; }
   ...
   public int z { get; set; }
}

我想使用带有正文的PATCH请求更新MyClass的资源

{"a":42,"c":42}

使用ServiceStack是否有标准或推荐的方法来实现这一目标?

2 个答案:

答案 0 :(得分:4)

将DTO中的任何标量值声明为可为空。这将允许您确定在请求中实际发送了哪些字段:

public class MyClass {
    public int? a { get; set; }
    public int? b { get; set; }
    public int? c { get; set; }
    // etc.
    // object-type properties are already nullable of course
    public string MyString { get; set; }
}

现在,如果客户端发送部分请求,请执行以下操作:

{ "a": 1, "b": 0 }

在检查DTO时,您将能够确定实际发送了哪些属性:

myClass.a == 1
myClass.b == 0
myClass.c == null
myClass.MyString == null
etc.

为您的DTO设置PATCH路线并在您的服务中实施Patch方法:

public object Patch(MyClass request)
{
    var existing = GetMyClassObjectFromDatabase();
    existing.PopulateWithNonDefaultValues(request);
    SaveToDatabase(existing);
    ...
}

PopulateWithNonDefaultValues是关键所在。它会将请求对象中的值复制到数据库实体上,但只会复制不是默认值的属性。因此,如果值为null,则不会复制它,因为客户端没有为其发送值。请注意,它将复制整数值为零,因为我们将其设置为可为空的int,并且此方法将可空int的默认值视为null,而不是零。将DTO属性声明为可为空可能不会对代码的其余部分造成太大麻烦。

请注意,此方法可以轻松使用JSON。如果您需要支持XML请求/响应,则可能需要对DataContract/DataMember属性进行一些额外的工作,以确保正确处理空值。

答案 1 :(得分:2)

虽然esker的回复很好但我想补充一点,对于可空字段可能还不够 - 因为你不知道反序列化器或用户是否创建了那个空字段。

一种方法是查看原始请求。

另一种方法是要求用户提供额外的请求(查询字符串)参数,以清楚地指定要修补的字段。 类似于:patch_fields = name,description,field3 这种方法的好处是最终用户可以更好地控制修补,并且不会错误地覆盖一个值(因为他使用了原始实体而忘记清除某些字段)