-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: ensure valid jsonapi error members are accessible #8669
Conversation
// Keep only what are valid attr's for a jsonapi error | ||
extracted[key].push({ | ||
id: error.id, | ||
links: error.links ? { about: error.links.about, type: error.links.type } : undefined, | ||
status: error.status, | ||
code: error.code, | ||
detail: error.detail, | ||
title: error.title, | ||
meta: error.meta | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each of these keys might be undefined. That's a bit messy, and I would clean this up before seeking final approval / merge by only defining keys that are set in the error.
At this stage I just put this together to demonstrate the approach and show that it works.
let errorsHash = serializer.extractErrors(store, store.modelFor(identifier.type), error, identifier.id) as Record< | ||
string, | ||
string | string[] | ||
string | string[] | JsonApiError[] | ||
>; | ||
error.errors = errorsHashToArray(errorsHash); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our internal extractErrors()
hook now returns JsonApiError[]
but is still backwards compatible with hooks that users might have defined that return string | string[]
if (typeof error === 'string') { | ||
out.push({ | ||
title: title, | ||
detail: error, | ||
source: { | ||
pointer: pointer, | ||
}, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
backwards compatible - this should produce the exact same error as before if their extractErrors hook returned a string or string[]
} else { | ||
out.push({ | ||
...error, | ||
title: title, | ||
detail: error.detail || error.title, | ||
source: { | ||
pointer: pointer, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the full JsonApiError array was handed to this function, we produce an error that contains all the other (spec-complaint) error members, but we make sure it still has the title/detail/source as this function produced before.
extracted[key] = extracted[key] || []; | ||
extracted[key].push(error.detail || error.title); | ||
} | ||
const errorPointer = error.source?.pointer ?? '/data' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see: https://jsonapi.org/format/#error-objects
allows for source
to be omitted
source: an object containing references to the primary source of the error. It SHOULD include one of the following members or be omitted:
Overall +1 on the approach, lets refine and add some tests. |
if (errorsHash) { | ||
Object.keys(errorsHash).forEach((key) => { | ||
let errorsItem = errorsHash[key] | ||
let errors = typeof errorsItem === 'string' ? [errorsItem] : errorsItem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably we should assert if not an array and not a string
}); | ||
} else { | ||
out.push({ | ||
...error, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the only thing about this that gives me pause is that this results in a grey middle ground of having passed the error through unchanged but also having changed it into json:api form.
But since the overall recommendation is to not have the extractErrors hook (and also more broadly we are beginning to move away from these legacy patterns) this seems fine as a compromise.
@Techn1x were you going to continue on this one? |
@runspired I think I'm going to drop it. Since then, I've just set Happy for you to close this, or carry it forward, up to you. At the time I pushed this I was a little frustrated at the LTS versions of ember-data;
Our upgrade path was 3.28 -> 4.6 (back in Dec 2022), and then 4.6 -> 4.12 (about a month ago). I was having to avoid the 4.4/4.8 LTS versions to get the fixes I needed, which doesn't make a whole lot of sense. So I was keen to fix the error handling thing without needing to rewrite my backend, and give back to help improve the LTS versions specifically because of the pain I went through. But... time passed and I've come around to just setting I've been running 4.12 for a while now (with |
Thanks for reviewing the PR and being receptive to the changes ❤️ |
@Techn1x totally get it. I do think 3.28 -> 4.4 -> 4.6 -> 4.12 was a better path than 4.8, I tried hard to patch 4.8 but ultimately the shift's effects took till 4.12 to fully shake out. TBH the EC issue was a big part of that, it was hard to figure out the right fix - we tried a lot of things - and it was also annoying to be adding a hack to work around what an external library shouldn't have been doing in the first place.
I think you missed what I said about it here in the original issue: #8188 (comment) Or maybe it's the nuance. extractErrors was never part of the public API. In an ideal world, the default for most people should be that they were never using it and it didn't exist on their serializer. For these people, nothing breaks. Where idealism broke down is too many people blindly extended RESTSerializer and JSONApiSerializer when they should have written their own. But even for these folks if they were only using errors the way that EmberData had intended to surface errors then also nothing breaks. You fell into a camp that I hoped no one was in (and still suspect not many people are in) where you did not write your own serializer and also did not use errors the way EmberData had intended to surface them. The unfortunate reality of Javascript being that whether something is documented or not if you stick a property on an object people will see it. I'm still obviously sympathetic and very willing to ease the path for the next poor fellow, but also as you noted the fix really is as simple as "delete that method from your serializer and move on". |
Yeah I can only imagine the challenges of trying to backport certain fixes in any repo that has LTS versions..
I didn't miss it, but may have misinterpreted this line Didn't realise (at the time) that I had to actually set extractErrors to false to override the function set in JSONAPISerializer that I was/am extending
I thought that was what we're supposed to do... definitely been doing that for many years and seen it at multiple workplaces. Seems the guides indicate it too, but I suspect I might be misunderstanding your words here
💯 and I understand that now |
The guides have never been in the control of the project, and unfortunately the folks that wrote them felt differently than the library authors on what constituted a good experience. The guides largely attempt to minimize setup, configuration and writing code. I find this unrealistic when it comes to APIs, every API is very different and has nuances only its authors can understand. |
Description
An attempt to resolve issues detailed in #8188
Notes for the release
The error handling was changed in 4.7.3 to require the use of these functions, so I think this fix for those functions to correctly parse jsonapi error members should be backported to 4.8 LTS and 4.12 LTS
I think this fix is important, as it will help folks get to 4.8 and beyond to ember-data 5.
I would also like to point out the Ember guides are incorrect, but I'm not sure where/how to edit those at this time.
https://jsonapi.org/format/#error-objects spec says it should be
/data
but the guides saydata
https://api.emberjs.com/ember-data/4.12/classes/JSONAPISerializer/methods/extractErrors?anchor=extractErrors