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

dan*_*979 22 ember.js ember-data json-api ember-cli

我使用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", 
    }
]}
Run Code Online (Sandbox Code Playgroud)

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

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

指针:请求文档中关联实体的JSON指针[RFC6901] [例如,主数据对象的"/ data",或特定属性的"/ data/attributes/title"].

parameter:一个字符串,指示导致错误的查询参数.

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

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

谢谢.

Sar*_*rus 87

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

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: -------------------------------
Run Code Online (Sandbox Code Playgroud)

遗憾的是,错误处理文档分散在各处,因为您处理不同适配器(Active,REST,JSON)的错误的方式有点不同.

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

您会注意到API仅指定在键入的顶级数组中返回错误,errors并且所有其他错误属性都是可选的.所以看起来JSON API需要的是以下内容:

{
    "errors": [
     {}
    ]
}  
Run Code Online (Sandbox Code Playgroud)

当然,这对于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"
         }
     }
    ]
}  
Run Code Online (Sandbox Code Playgroud)

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

最后,您必须使用HTTP代码返回验证错误,422这意味着"Unprocessable Entity".如果您没有返回422代码,那么默认情况下,Ember Data将返回一个AdapterError并且不会在模型的errors哈希上设置错误消息.这让我有一段时间,因为我使用HTTP代码400(错误请求)将验证错误返回给客户端.

ember数据区分两种类型错误的方式是验证错误返回一个InvalidError对象(http://emberjs.com/api/data/classes/DS.InvalidError.html).这将导致errors设置模型上的哈希值,但不会将isError标志设置为true(不确定为什么会出现这种情况,但请在此处记录: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)
}
Run Code Online (Sandbox Code Playgroud)

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

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

model.get('errors.isAdmin');
Run Code Online (Sandbox Code Playgroud)

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

[
   {
      "attribute": "isAdmin",
      "message": "The attribute `is-admin` is required"
    }
]
Run Code Online (Sandbox Code Playgroud)

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

{{#each model.errors.isAdmin as |error|}}
    <div class="error">
      {{error.message}}
    </div>
{{/each}}
Run Code Online (Sandbox Code Playgroud)

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

如果您的API不使用HTTP 422代码进行验证错误(例如,如果它使用400),那么您可以通过覆盖handleResponse自定义适配器中的方法来更改JSONAPIAdapter的默认行为.下面是一个示例,它返回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);
  }
});
Run Code Online (Sandbox Code Playgroud)

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

希望有所帮助!

  • 在撰写8个月之后,这个SO的回答仍然是Ember.js路由中使用默认适配器进行错误处理的最长和最简洁的文档. (20认同)
  • 您可能不需要覆盖`handleResponse`方法......相反,您可以简单地重新定义`isInvalid`方法以查找400状态以及默认422.请参阅此处:https://github.com/emberjs /data/blob/v1.13.10/packages/ember-data/lib/adapters/rest-adapter.js#L879 (4认同)
  • 我希望我可以多次投票.非常感谢! (3认同)