【问题标题】:Adding validation information to REST responses向 REST 响应添加验证信息
【发布时间】:2013-03-14 08:57:21
【问题描述】:

我正在尝试构建一个(主要是)宁静的服务,但我在设计的一部分方面遇到了困难。我们公开各种资源,在服务器端如下所示:

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

Resource 是一个基类:

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

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

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

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

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

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

tl;dr;

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

【问题讨论】:

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


    【解决方案1】:

    也许是这样的,

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        如果我正确理解您的问题,您可以执行这样的解决方案:

            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。

        【讨论】:

          猜你喜欢
          • 2017-04-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-04
          • 1970-01-01
          • 1970-01-01
          • 2022-08-06
          相关资源
          最近更新 更多