我试图建立一个(大部分)宁静的服务,但我正在努力设计的一部分。我们公开了各种资源,在服务器端看起来像:
public class Thing1 : Resource {
public string ABC {get;set;}
public string DEF {get;set;}
}
Resource
是基类:
public class Resource {
public List<Link> Links {get;set;}
}
Link
s依次绑定rel
和uri
s。通过这种方式,每个Resource
都有到其他资源等的链接,消费者可以浏览服务提供的各种资源。
某些(但不是全部)资源是可编辑的,因此,使用者将检索资源,对其进行更改,然后PUT
将这些更改重新发送回服务。当然,此时,服务将根据需要执行验证(并处理任何并发问题)。
但是,与往常一样,如果消费应用程序在尝试PUT
请求之前可以预先执行某些验证,减少不必要的往返行程(就像我们可能的那样)即使服务器必须重复它,也要使用javascript验证。)
因此,我想在我们的回复中包含一些验证信息,以便消费应用程序知道(例如),ABC
不能超过6个字符。应该注意的是,目前,消费者可以使用相同的资源类(它们在一个单独的程序集中,与适当的MediaTypeFormatter
类一起) - 添加属性(例如System.ComponentModel.DataAnnotations.RequiredAttribute
}感觉不对,因为消费应用程序最终得到了验证,就像它们在共享程序集中一样,而不是在服务中现在。
还有一些基于策略的验证,其中直到运行时才能计算实际验证属性。
TL;博士;
什么是包含&#34;有用的&#34; REST响应中的验证信息以及实际资源,以便消费应用程序可以构建良好的用户体验?
答案 0 :(得分:3)
也许像是,
> GET /api/Thing/1
< 200 OK
< Content-Type: application/vnd.acme.resource+xml
<resource>
<ABC>blah</ABC>
<DEF>blurg</DEF>
<links>
<links rel="help" href="/api/help/things"/>
<links rel="http://acme.com/rels/validationrules" href="/api/validationrules/things"/>
</links>
</resource>
> GET /api/validationrules/things
< 200 OK
< Content-Type: application/vnd.acme.validationrules+xml
<rules resourceType="thing">
<property name="ABC" MaxLength="6"/>
<property name="DEF" MaxLength="8"/>
</rules>
我在自己的API中做了类似的事情。遗憾的是,我没有注意到尝试解决这一特殊需求的标准媒体类型。我怀疑试图定义这种类型的媒体类型导致“厨房水槽”效应,每个人都有不同的要求,他们都被抛入,最终结果是每个人都太复杂。
但是,定义满足您特定需求的媒体类型可能是一项非常易于管理的挑战。
在我看来,关于此解决方案的重要一点是,/api/validationrules/things
应该很少更改,因此可以由客户端私下缓存。这意味着客户支付非常低的成本,可以将此信息作为独特资源进行检索。
答案 1 :(得分:1)
如果您有足够的预算(时间,金钱或两者),请为资源构建metaservice,以便您的其余部分仅返回数据(带有元数据标识符),如果客户端需要,则可以请求数据的验证元数据它收到了。这样,您只需发送客户需要的内容,并合理分离蛋黄和白色。
作为一种实现变体,对于每个请求/some/res/ource
,您都可以创建一个伴随/some/res/ource/meta
,它将返回有关该资源的只读元。鉴于路径几乎相同,您可以将您的验证定义为类成员的属性,而metaservice只需从路径中找到一个类,并从类定义构建验证信息。
答案 2 :(得分:-1)
如果我正确理解您的问题,您可以执行此类解决方案:
public class ServiceResponse
{
private List<Exception> exceptions = new List<Exception>();
public List<Exception> Errors { get { return exceptions; } }
private string password;
public string Password
{
get
{
return password;
}
set
{
if (string.IsNullOrEmpty(value))
{
exceptions.Add(new ArgumentException("Password cannot be empty!"));
}
if (value != null && value.Length < 10)
{
exceptions.Add(new ArgumentException("Password is too short!"));
}
if (exceptions.Count == 0)
{
password = value;
}
//else throw an Exception that errors were occured or do nothing
}
}
}
然后您可以检查错误属性是否有任何错误,如果有,则会显示所有错误或您想要的任何错误。在这种情况下,在所有内容都正确之前,不会设置属性“密码”。硬编码错误消息可以用资源字符串替换。结果,您发送的响应可以在客户端正确处理,无需任何JavaScript。