向REST响应添加验证信息

时间:2013-03-14 08:57:21

标签: c# rest asp.net-web-api

我试图建立一个(大部分)宁静的服务,但我正在努力设计的一部分。我们公开了各种资源,在服务器端看起来像:

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依次绑定reluri s。通过这种方式,每个Resource都有到其他资源等的链接,消费者可以浏览服务提供的各种资源。

某些(但不是全部)资源是可编辑的,因此,使用者将检索资源,对其进行更改,然后PUT将这些更改重新发送回服务。当然,此时,服务将根据需要执行验证(并处理任何并发问题)。

但是,与往常一样,如果消费应用程序在尝试PUT请求之前可以预先执行某些验证,减少不必要的往返行程(就像我们可能的那样)即使服务器必须重复它,也要使用javascript验证。)

因此,我想在我们的回复中包含一些验证信息,以便消费应用程序知道(例如),ABC不能超过6个字符。应该注意的是,目前,消费者可以使用相同的资源类(它们在一个单独的程序集中,与适当的MediaTypeFormatter类一起) - 添加属性(例如System.ComponentModel.DataAnnotations.RequiredAttribute}感觉不对,因为消费应用程序最终得到了验证,就像它们在共享程序集中一样,而不是在服务中现在

还有一些基于策略的验证,其中直到运行时才能计算实际验证属性。

TL;博士;

什么是包含&#34;有用的&#34; REST响应中的验证信息以及实际资源,以便消费应用程序可以构建良好的用户体验?

3 个答案:

答案 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。