Skip to content

Conversation

felixarntz
Copy link
Member

Follow up to #78: This brings ResponseException::fromInvalidData more in line with ResponseException::fromMissingData, making the exception messages more helpful by including the concrete response field name where the problem occurred.

@felixarntz felixarntz added this to the 0.2.0 milestone Oct 1, 2025
@felixarntz felixarntz added the [Type] Enhancement A suggestion for improvement. label Oct 1, 2025
Copy link

github-actions bot commented Oct 1, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: felixarntz <[email protected]>
Co-authored-by: JasonTheAdams <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copy link
Member

@JasonTheAdams JasonTheAdams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the modification in the exception, @felixarntz! I'm a bit 🤔 about one specific implementation of it.

*/
protected function parseResponseChoiceToCandidate(
array $choiceData,
int $index,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not crazy about requiring this parameter that's strictly used for the exception. This method otherwise isn't coupled to the concept that there's an index somehow associated with the choice. If we feel the index is really important (and the $choiceData isn't sufficient), I'd rather throw the exception where the loop is happening — even if it means catching this exception in the loop and throwing a new one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's totally fair. I'll take another look later to see how this could be restructured.

Copy link
Member Author

@felixarntz felixarntz Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JasonTheAdams Looking into this, I'm not sure what's the best alternative - everything ends up being hacky somehow.

You could do something where the inner methods (without awareness of $index) simply pass the innermost field name (e.g. message instead of choices[{$index}].message), and then the outer method catches it and runs a regular expression on $e->getMessage() to replace "([A-Za-z0-9_]+)" with "choices[{$index}].$1", but that's hacky because it is based on the specific message shape of the ResponseException class. - I don't love it.

Other ideas I thought about is to store the API name and field name as separate properties in ResponseException so you can read them from the caught instance, but then you also still need to somehow extract the part of the message that's dynamic and doesn't just come from the API name and field name. Not a great solution either.

Let me know if you have other ideas.

Otherwise, I think the current approach of passing something to the inner methods is the most straightforward. An idea that might alleviate your concern would be that we don't just pass the index, but the full "prefix" identifier of the current context that is being parsed, e.g. instead of $index (integer) we would pass choices[{$index}] (string). This not only clarifies the purpose of why this is passed, it also avoids the problem of the inner methods having some awareness of their context (e.g. right now the methods must know that the outer field is called choices, which is not ideal) - by passing the context down in its entirety the responsibility remains entirely with the outer method, and as such, in a single place within the class.

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm starting to back down on this one. I admit I didn't notice the first time that this is a protected method (and could maybe even be private). If this is just an internal method, then I don't think passing the index is a big deal. It feels a little odd since it's just used for exceptions, but that would be more strange if it was public.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, sounds good. I think it still needs to be protected so that custom tools in e.g. a specific provider can be supported (by overriding some of these methods in a child class), but yeah the risk should be rather low. Also as long as we're in such an early version, for such low-level semi-internal APIs we can still make breaking changes if we later find there's a problem.

LMK if this works for you.

Copy link
Member

@JasonTheAdams JasonTheAdams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@JasonTheAdams JasonTheAdams merged commit 983d66e into trunk Oct 8, 2025
16 of 17 checks passed
@JasonTheAdams JasonTheAdams deleted the enhance/response-exception-invalid-value branch October 8, 2025 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants