使用(现在默认)Ember Data JSON-API 适配器处理错误

Handling errors with the (now default) Ember Data JSON-API adapter

我正在使用 Ember 1.13.7 和 Ember Data 1.13.8,默认情况下使用 JSON-API 标准来格式化发送到的有效负载并从 API.

收到

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

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

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

source: an object containing references to the source of the error, optionally including any of the following members:

pointer: a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].

parameter: a string indicating which query parameter caused the error.

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

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

谢谢。

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

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 仅指定错误在由 errors 键入的顶级数组中 returned,所有其他错误属性都是可选的。所以看起来 JSON API 需要的是以下内容:

{
    "errors": [
     {}
    ]
}  

当然,这不会真正做任何事情,所以对于使用 Ember 数据和 JSONAPI 适配器开箱即用的错误,您需要包含在最小 detail 属性和 source/pointer 属性。 detail 属性被设置为错误消息,source/pointer 属性让 Ember 数据找出模型中的哪个属性导致了问题。因此 JSON API 数据所需的有效 JSON API 错误对象(如果您使用 JSONAPI 现在是默认值)就像这个:

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

请注意,detail 不是复数(这是我常犯的错误),source/pointer 的值不应包含前导正斜杠,并且属性名称应使用破折号。

最后,您必须 return 使用 HTTP 代码 422 的验证错误,这意味着 "Unprocessable Entity"。如果您没有 return 422 代码,那么默认情况下 Ember 数据将 return 和 AdapterError 并且不会在模型的 [=18] 上设置错误消息=]哈希。这让我有点头疼,因为我使用 HTTP 代码 400(错误请求)向客户端发送 return 验证错误。

ember 数据区分两种类型错误的方式是验证错误 return 是 InvalidError 对象 (http://emberjs.com/api/data/classes/DS.InvalidError.html). This will cause the errors hash on the model to be set but will not set the isError flag to true (not sure why this is the case but it is documented here: http://emberjs.com/api/data/classes/DS.Model.html#property_isError)。默认情况下,除 422 之外的 HTTP 错误代码将导致 AdapterError 被 returned 并且 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 代码 returned 是 422 并且您有正确的 JSON API 错误格式,那么您可以通过访问模型的错误散列,其中散列键是您的属性名称。哈希以驼峰格式键入属性名称。

例如,在我们上面的 json-api 错误示例中,如果 is-admin 上有错误,您将像这样访问该错误:

model.get('errors.isAdmin');

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

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

本质上是detail映射到messagesource/pointer映射到attribute。如果您在单个属性上有多个验证错误,则数组被 returned(JSON API 允许您 return 多个验证错误而不是 returning只是第一次验证失败)。您可以像这样在模板中直接使用错误值:

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

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

如果您 API 不使用 HTTP 422 验证错误代码(例如,如果它使用 400),那么您可以更改 JSONAPIAdapter 通过覆盖自定义适配器中的 handleResponse 方法。这是一个示例,其中 return 为任何 400.

的 HTTP 响应状态代码创建了一个新的 InvalidError 对象
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 和 return。这将导致与期望 422 HTTP 状态代码的默认行为相同的行为(即,将处理您的 JSON API 错误,并将消息放入错误散列中模型)。

希望对您有所帮助!