使用(现在默认)Ember Data JSON-API 适配器处理错误 [英] Handling errors with the (now default) Ember Data JSON-API adapter

查看:16
本文介绍了使用(现在默认)Ember Data JSON-API 适配器处理错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

{"错误":[{"title":"包含的.1.attributes.街道名称字段是必需的.","code":"API_ERR","状态":"400",}]}

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

<块引用>

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

<块引用>

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

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

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

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

谢谢.

解决方案

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

调试: -------------------------------ember.debug.js:5442DEBUG: Ember: 1.13.8ember.debug.js:5442DEBUG:Ember 数据:1.13.9ember.debug.js:5442DEBUG: jQuery: 1.11.3调试: -------------------------------

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

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

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

<代码>{错误":[{}]}

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

<代码>{错误":[{"detail": "属性`is-admin` 是必需的",来源": {指针":数据/属性/is-admin"}}]}

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

最后,您必须使用 HTTP 代码 422 返回验证错误,这意味着不可处理的实体".如果您不返回 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).默认情况下,422 以外的 HTTP 错误代码将导致返回 AdapterError 并且 isError 标志设置为 true>.在这两种情况下,promise 的拒绝处理程序都会被调用.

model.save().then(function(){//耶!有效}, 功能(){//由于某种原因它失败了可能是一个错误的请求 (400)//可能是验证错误 (422)}

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

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

model.get('errors.isAdmin');

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

<预><代码>[{"属性": "isAdmin","message": "属性`is-admin` 是必需的"}]

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

{{#each model.errors.isAdmin as |error|}}<div class="错误">{{错误信息}}

{{/每个}}

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

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

从ember-data"导入DS;从ember"导入 Ember;导出默认 DS.JSONAPIAdapter.extend({处理响应:函数(状态,标题,有效载荷){if(status === 400 &&payload.errors){返回新的 DS.InvalidError(payload.errors);}返回 this._super(...参数);}});

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

希望有帮助!

I am using Ember 1.13.7 and Ember Data 1.13.8, which by default use the JSON-API standard to format the payloads sent to and received from the API.

I would like to use Ember Data's built-in error handling in order to display red "error" form fields to the user. I have formatted my API error responses as per the JSON-API standard, e.g.

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

and when I attempt to save my model the error callback is being correctly executed. If I look within the Ember Inspector I can see that the model's "isError" value is set to true but I can't see how Ember Data is supposed to know which field within the model is the one in an error state? I see from the official JSON-API pages (http://jsonapi.org/format/#errors) that you can include a "source" object within the error response:

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.

but is this what I should be doing in order to tell Ember Data which fields it should mark as being in an error state?

If anyone can help shed some light on this I'd be grateful.

Thanks.

解决方案

Note the answer below is based on the following versions:

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: -------------------------------

The error handling documentation is unfortunately scattered around at the moment as the way you handle errors for the different adapters (Active, REST, JSON) are all a bit different.

In your case you want to handle validation errors for your form which probably means validation errors. The format for errors as specified by the JSON API can be found here: http://jsonapi.org/format/#error-objects

You'll notice that the API only specifies that errors are returned in a top level array keyed by errors and all other error attributes are optional. So seemingly all that JSON API requires is the following:

{
    "errors": [
     {}
    ]
}  

Of course that won't really do anything so for errors to work out of the box with Ember Data and the JSONAPIAdapter you will need to include at a minimum the detail attribute and the source/pointer attribute. The detail attribute is what gets set as the error message and the source/pointer attribute lets Ember Data figure out which attribute in the model is causing the problem. So a valid JSON API error object as required by Ember Data (if you're using the JSONAPI which is now the default) is something like this:

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

Note that detail is not plural (a common mistake for me) and that the value for source/pointer should not include a leading forward slash and the attribute name should be dasherized.

Finally, you must return your validation error using the HTTP Code 422 which means "Unprocessable Entity". If you do not return a 422 code then by default Ember Data will return an AdapterError and will not set the error messages on the model's errors hash. This bit me for a while because I was using the HTTP Code 400 (Bad Request) to return validation errors to the client.

The way ember data differentiates the two types of errors is that a validation error returns an InvalidError object (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). By default an HTTP error code other than 422 will result in an AdapterError being returned and the isError flag set to true. In both cases, the promise's reject handler will be called.

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

By default if the HTTP code returned is a 422 and you have the correct JSON API error format then you can access the error messages by accessing the model's errors hash where the hash keys are your attribute names. The hash is keyed on the attribute name in the camelcase format.

For example, in our above json-api error example, if there is an error on is-admin your would access that error like this:

model.get('errors.isAdmin');

This will return an array containing error objects where the format is like this:

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

Essentially detail is mapped to message and source/pointer is mapped to attribute. An array is returned in case you have multiple validation errors on a single attribute (JSON API allows you to return multiple validation errors rather than returning just the first validation to fail). You can use the error values directly in a template like this:

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

If there are no errors then the above won't display anything so it works nicely for doing form validation messages.

If you API does not use the HTTP 422 code for validation errors (e.g., if it uses 400) then you can change the default behavior of the JSONAPIAdapter by overriding the handleResponse method in your custom adapter. Here is an example that returns a new InvalidError object for any HTTP response status code that is 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);
  }
});

In the above example I'm checking to see if the HTTP status is 400 and making sure an errors property exists. If it does, then I create a new DS.InvalidError and return that. This will result in the same behavior as the default behavior that expects a 422 HTTP status code (i.e., your JSON API error will be processed and the message put into the errors hash on the model).

Hope that helps!

这篇关于使用(现在默认)Ember Data JSON-API 适配器处理错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆