Ember/Phoenix应用使用JSONAPIAdapter发起POST请求时AdapterError报错
为什么Ember会抛出
AdapterError expects json-api formatted errors array错误? 这个问题我之前也碰到过,核心原因是Ember的JSONAPIAdapter严格遵循JSON:API规范,而你的Phoenix后端返回的错误响应结构不符合这个规范。
问题根源
JSON:API规范明确要求错误响应的errors字段必须是一个数组,每个数组元素是包含错误详情的对象(比如要包含detail、source等属性)。举个符合规范的错误响应示例:
{ "errors": [ { "detail": "can't be blank", "source": { "pointer": "/data/attributes/name" } } ] }
但你的Phoenix后端返回的是:
{"errors":{"name":["can't be blank"]}}
这是Phoenix默认的Changeset错误格式——errors是一个对象,键是字段名,值是错误信息数组,完全不符合JSON:API的数组要求,所以Ember的适配器会抛出断言错误。
两种解决方案
方案1:修改Phoenix后端,返回符合JSON:API的错误格式
在Phoenix的控制器中,自定义错误处理逻辑,把Changeset的错误转换成JSON:API要求的数组结构。
首先在控制器里添加一个辅助函数,用于转换错误格式:
defp json_api_errors(changeset) do Enum.map(Ecto.Changeset.traverse_errors(changeset, &translate_error/1), fn {field, messages} -> %{ detail: hd(messages), source: %{ pointer: "/data/attributes/#{Atom.to_string(field)}" } } end) end
然后在处理创建失败的逻辑中使用这个函数:
def create(conn, %{"data" => data}) do case Listings.create_listing(data) do {:ok, listing} -> render(conn, "show.json", listing: listing) {:error, %Ecto.Changeset{} = changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{errors: json_api_errors(changeset)}) end end
这样后端返回的错误就完全符合Ember的要求了。
方案2:在Ember端适配后端的错误格式
如果暂时不想修改后端,可以在Ember的适配器中重写handleResponse方法,把后端的错误对象转换成JSON:API规范的数组格式。
修改adapter/application.js:
import DS from 'ember-data'; import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin'; import config from '../config/environment'; export default DS.JSONAPIAdapter.extend(DataAdapterMixin, { handleResponse(status, headers, payload) { // 检测到后端返回的错误是对象格式时,进行转换 if (payload && payload.errors && typeof payload.errors === 'object' && !Array.isArray(payload.errors)) { const formattedErrors = Object.entries(payload.errors).map(([field, messages]) => { return { detail: messages[0], source: { pointer: `/data/attributes/${field}` } }; }); payload.errors = formattedErrors; } return this._super(status, headers, payload); } });
这个方法会在适配器处理响应前,把后端的错误对象转换成Ember期望的数组结构,从而避免断言错误。
内容的提问来源于stack exchange,提问作者guy1997
相关产品推荐
相关产品推荐

