10

我正在尝试构建一个(大部分)宁静的服务,但我正在努力解决设计的一部分。我们公开各种资源,在服务器端如下所示:

public class Thing1 : Resource {
  public string ABC {get;set;}
  public string DEF {get;set;}
}

Resource基类在哪里:

public class Resource {
  public List<Link> Links {get;set;}
}

where Links,反过来,只是绑定rels 和uris。通过这种方式,每个Resource都有指向其他资源等的链接,消费者可以浏览服务提供的各种资源。

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

但是,和往常一样,如果消费应用程序可以在尝试请求之前预先执行一些验证PUT,以减少不必要的往返行程(这与我们可能使用 javascript 验证的方式非常相似,即使服务器已经重复一遍)。

所以,我想在我们的响应中包含一些验证信息,以便消费应用程序知道(例如)ABC不能超过 6 个字符。应该注意的是,目前,消费者可以使用相同的资源类(它们在一个单独的程序集中,以及适当的MediaTypeFormatter类)——添加属性(例如System.ComponentModel.DataAnnotations.RequiredAttribute)感觉不对,因为消费应用程序最终以验证为那是在他们使用共享程序集的时候,而不是现在在服务中。

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

tl;博士;

什么是在 REST 响应中包含“有用”验证信息以及实际资源的良好设计,以便使用应用程序可以构建良好的用户体验?

4

3 回答 3

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应该很少更改,因此可以由客户端私下缓存。这意味着客户只需支付非常少的成本即可将该信息作为不同的资源进行检索。

于 2013-03-14T15:09:11.107 回答
1

如果您有足够的预算(时间、金钱或两者兼有),请为资源构建一个元服务,以便您的其余部分只返回数据(带有元数据标识符),并且如果客户需要,它可以为刚收到的数据请求验证元数据. 这样,您只发送客户需要的东西并合理分离蛋黄和蛋白。

作为一种实现变体,对于每个请求,/some/res/ource您都可以创建一个伴侣,该伴侣/some/res/ource/meta将返回有关该资源的只读元数据。鉴于路径几乎相同,您可以将验证定义为类成员的属性,并且元服务将简单地从路由中找到一个类并从类定义中构建验证信息。

于 2013-03-14T13:07:46.533 回答
-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
            }
        }
    }

然后您可以检查Errors属性是否有任何错误,如果有则显示所有错误或您想要的任何错误。在这种情况下,在一切正确之前不会设置属性“密码”。硬编码的错误消息可以替换为资源字符串。结果,您发送的响应可以在客户端正确处理而无需任何 javascript。

于 2013-03-14T14:28:27.310 回答