Repository navigation
fix: honor accessor status and add 204 path in ProductController | MC-16536 - #400
Merged
Merged
Conversation
…-16536 ProductController.buildResponse() derived the HTTP status purely from result.getChallenges() presence, ignoring any explicit AccessorResponse.getStatus() the accessor set. This made ProductAccessor's .withStatus(OK) dead code whenever a terminal response still carries a trailing challenge (e.g. CPB's account_opening_success), so it silently returned 202 instead of 200. There was also no path to 204 at all, which Rev 6 requires when a product is no longer available. Mirrors PayeesController.addPayee()'s existing, correct pattern: accessor status wins when set; challenge-derived 200/202 remains the default when it isn't. NO_CONTENT is checked before the null-result check so 'no longer available' (204) and 'never existed' (404) stay distinguishable.
SandhyaBhatia
requested review from
gerfboy,
mattnichols,
meotch,
stevecl5 and
tessstoddard
as code owners
October 2, 2026 22:22
mattnichols
approved these changes
Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary of Changes
ProductController.buildResponse()derived the HTTP status purely from whetherresult.getChallenges()was non-empty, completely ignoring any explicitAccessorResponse.getStatus()the accessor had set. This made an accessor's.withStatus(PathResponseStatus.OK)dead code whenever the result still carried atrailing challenge — which is exactly what
path-accessor-central-pacific's CPBaccount-opening terminal response does intentionally (it keeps the
account_opening_successchallenge alongsidestatus: COMPLETEso moneymobilex canrender the success screen from it). The practical effect: that terminal call likely
returns 202 where 200 is spec-correct, and no one has noticed because
moneymobilex doesn't check the HTTP status for that step — it keys off
challenges[0].id == "account_opening_success"as a string match instead.There was also no path to
204 No Contentat all. Per the Gutenberg spec(
mdx/product/_spec.md.erb, Update a product), the PUT endpoint must return 202 whilechallenged, 200 while the product remains available, and 204 if it's no longer
available.
buildResponse()could only ever produce 200, 202, or 404.PayeesController.addPayee()already has the correct pattern elsewhere in this samecodebase:
ProductController.buildResponse()now follows that same pattern, plus the newNO_CONTENTpath:The
NO_CONTENTcheck runs before the null-result check so "product existed and isnow gone" (204) stays distinguishable from "product id never existed" (404) — those
are different accessor outcomes and shouldn't collapse to the same response.
This is the companion fix to MC-16523
(
path-accessor-central-pacificRev 6 change) — that ticket's terminal response relieson this fix to actually return 200.
Fixes # (issue)
https://mxcom.atlassian.net/browse/MC-16536
Public API Additions/Changes
ProductController(mdx-web/src/main/java/com/mx/path/model/mdx/web/controller/ProductController.java):buildResponse()(private) now readsAccessorResponse.getStatus()first and usesit directly when set, instead of always recomputing the status from
result.getChallenges().PathResponseStatus.NO_CONTENT→ HTTP204 No Contentbranch, checkedbefore the existing null-result →
404branch.getProduct,updateProduct) — this is internal tobuildResponse().Downstream Consumer Impact
Non-breaking for any accessor that doesn't set
AccessorResponse.getStatus()—buildResponse()falls back to the exact same challenge-derived 200/202 logic asbefore for those, unchanged.
For accessors that do set an explicit status (currently just
path-accessor-central-pacific'sProductAccessor, once MC-16523 ships), the HTTPstatus returned to the client will change to match what the accessor intended:
200 OKinstead of202 Accepted. Needs a QA capture against the live/preview CPB connector toconfirm this is the only consumer affected and that moneymobilex's behavior in
production is unaffected (per the ticket, moneymobilex doesn't branch on this
status code today, only on the challenge id, so this should be safe — but verifying
against a real capture before this reaches production is called out explicitly in
both MC-16523 and MC-16536).
PathResponseStatus.NO_CONTENTwill now correctly produce204instead of falling through to whateverbuildResponse()did with a nullresult before (previously
404, which was itself not spec-correct for this case).No migration steps required for existing consumers that don't set an explicit status.
How Has This Been Tested?
Extended
ProductControllerTest.groovy(Spock) with 7 new cases alongside the 7existing ones, covering every branch combination:
OKwith non-empty challenges → controller returns200(not202) — the Rev 6 terminal-response case202(unchanged default, regression guard)200(unchanged default, regression guard)NO_CONTENT→ controller returns204with a null body404, even thoughNO_CONTENThandling now exists — confirms the two don't collapseOK-wins-over-challenges case repeated forgetProduct(GET), not justupdateProduct(PUT)NO_CONTENTcase repeated forgetProduct./gradlew :mdx-web:buildis fully green: 388 tests pass (14 inProductControllerTest), checkstyle/spotless/spotbugs all clean.Checklist: