23

我使用的是 Ember 1.13.7 和 Ember Data 1.13.8,它们默认使用 JSON-API 标准来格式化发送到 API 和从 API 接收的有效负载。

我想使用 Ember Data 的内置错误处理来向用户显示红色的“错误”表单字段。我已经按照 JSON-API 标准格式化了我的 API 错误响应,例如

{"errors":[
    {
        "title":"The included.1.attributes.street name field is required.", 
        "code":"API_ERR", 
        "status":"400", 
    }
]}

当我尝试保存我的模型时,错误回调正在正确执行。如果我在 Ember Inspector 中查看,我可以看到模型的“isError”值设置为 true,但我看不到 Ember Data 应该如何知道模型中的哪个字段处于错误状态?我从官方 JSON-API 页面 ( http://jsonapi.org/format/#errors ) 中看到,您可以在错误响应中包含“源”对象:

source:一个包含对错误源的引用的对象,可选地包括以下任何成员:

指针:指向请求文档中关联实体的 JSON 指针 [RFC6901] [例如,“/data”表示主要数据对象,或“/data/attributes/title”表示特定属性]。

参数:一个字符串,指示哪个查询参数导致错误。

但这是我应该做的,以便告诉 Ember Data 它应该将哪些字段标记为处于错误状态?

如果有人可以帮助阐明这一点,我将不胜感激。

谢谢。

4

1 回答 1

89

请注意,以下答案基于以下版本:

DEBUG: -------------------------------
ember.debug.js:5442DEBUG: Ember                     : 1.13.8
ember.debug.js:5442DEBUG: Ember Data                : 1.13.9
ember.debug.js:5442DEBUG: jQuery                    : 1.11.3
DEBUG: -------------------------------

不幸的是,错误处理文档目前分散在各处,因为您处理不同适配器(Active、REST、JSON)的错误的方式都有些不同。

在您的情况下,您想要处理表单的验证错误,这可能意味着验证错误。JSON API 指定的错误格式可以在这里找到:http: //jsonapi.org/format/#error-objects

您会注意到,API 仅指定错误在以 by 为键的顶级数组中返回,errors所有其他错误属性都是可选的。因此,似乎 JSON API 所需的一切如下:

{
    "errors": [
     {}
    ]
}  

当然,这不会真正做任何事情,因此对于使用 Ember Data 和 JSONAPIAdapter 开箱即用的错误,您至少需要包含detail属性和source/pointer属性。该detail属性是设置为错误消息的内容,该source/pointer属性让 Ember Data 找出模型中的哪个属性导致了问题。因此,Ember Data 所需的有效 JSON API 错误对象(如果您使用的是现在默认的 JSONAPI)如下所示:

{
    "errors": [
     {
        "detail": "The attribute `is-admin` is required",
        "source": {
             "pointer": "data/attributes/is-admin"
         }
     }
    ]
}  

请注意,这detail不是复数(对我来说是一个常见的错误),并且 for 的值source/pointer不应包含前导正斜杠,并且属性名称应被虚化。

最后,您必须使用 HTTP 代码返回您的验证错误,422这意味着“无法处理的实体”。如果您不返回422代码,则默认情况下 Ember Data 将返回一个AdapterError并且不会在模型的errors哈希上设置错误消息。这让我有点苦恼,因为我使用 HTTP 代码400(错误请求)将验证错误返回给客户端。

ember 数据区分这两种错误的方式是验证错误返回一个InvalidError对象 ( http://emberjs.com/api/data/classes/DS.InvalidError.html )。这将导致errors模型上的哈希被设置但不会将isError标志设置为真(不知道为什么会这样,但它记录在这里:http ://emberjs.com/api/data/classes/DS.Model .html#property_isError)。默认情况下,HTTP 错误代码422会导致AdapterError返回一个并且isError标志设置为true. 在这两种情况下,promise 的拒绝处理程序都会被调用。

model.save().then(function(){
    // yay! it worked
}, function(){
    // it failed for some reason possibly a Bad Request (400)
    // possibly a validation error (422)
}

默认情况下,如果返回的 HTTP 代码是 a422并且您具有正确的 JSON API 错误格式,那么您可以通过访问模型的错误哈希来访问错误消息,其中哈希键是您的属性名称。哈希以驼峰格式键入属性名称。

例如,在我们上面的 json-api 错误示例中,如果出现错误,is-admin您将访问该错误,如下所示:

model.get('errors.isAdmin');

这将返回一个包含错误对象的数组,格式如下:

[
   {
      "attribute": "isAdmin",
      "message": "The attribute `is-admin` is required"
    }
]

本质detail上被映射到message并被source/pointer映射到attribute. 如果您在单个属性上有多个验证错误,则会返回一个数组(JSON API 允许您返回多个验证错误,而不是只返回第一个验证失败)。您可以直接在模板中使用错误值,如下所示:

{{#each model.errors.isAdmin as |error|}}
    <div class="error">
      {{error.message}}
    </div>
{{/each}}

如果没有错误,那么上面将不会显示任何内容,因此它可以很好地用于执行表单验证消息。

如果您的 API 不使用 HTTP422代码来验证错误(例如,如果它使用),那么您可以通过覆盖自定义适配器中400的方法来更改 JSONAPIAdapter 的默认行为。handleResponse这是一个示例,它InvalidError为任何 HTTP 响应状态代码返回一个新对象,即400.

import DS from "ember-data";
import Ember from "ember";

export default DS.JSONAPIAdapter.extend({
  handleResponse: function(status, headers, payload){
    if(status === 400 && payload.errors){
      return new DS.InvalidError(payload.errors);
    }
    return this._super(...arguments);
  }
});

在上面的示例中,我正在检查 HTTP 状态是否为400并确保存在错误属性。如果是这样,那么我创建一个新的DS.InvalidError并返回它。这将导致与期望 HTTP 状态代码的默认行为相同的行为422(即,将处理您的 JSON API 错误并将消息放入模型上的错误哈希中)。

希望有帮助!

于 2015-08-17T20:55:11.483 回答