-
Notifications
You must be signed in to change notification settings - Fork 135
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
fine-grained errors reporting for PaymentAddress #712
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -490,6 +490,39 @@ <h3> | |
} | ||
</pre> | ||
</section> | ||
<section> | ||
<h3> | ||
Fine-grained error reporting | ||
</h3> | ||
<p> | ||
A developer can use the <a data-link-for= | ||
"PaymentDetailsUpdate">shippingAddressErrors</a> member of the | ||
<a>PaymentDetailsUpdate</a> dictionary to indicate that there are | ||
validation errors with specific attributes of a | ||
<a>PaymentAddress</a>. The <a data-link-for= | ||
"PaymentDetailsUpdate">shippingAddressErrors</a> member is a | ||
<a>AddressErrorFields</a> dictionary, whose members specifically | ||
demarcate the fields of a <a>physical address</a> that are erroneous | ||
while also providing helpful error messages to be displayed to the | ||
end user. | ||
</p> | ||
<pre class="example"> | ||
request.onshippingaddresschange = ev => { | ||
ev.updateWith(validateAddress(request.shippingAddress)); | ||
}; | ||
function validateAddress(shippingAddress) { | ||
const error = "Can't ship to this address."; | ||
const shippingAddressErrors = { | ||
cityError: "FarmVille is not a real place.", | ||
postalCodeError: "Unknown postal code for your country.", | ||
}; | ||
// Empty shippingOptions implies that we can't ship | ||
// to this address. | ||
const shippingOptions = []; | ||
return { error, shippingAddressErrors, shippingOptions }; | ||
} | ||
</pre> | ||
</section> | ||
<section data-link-for="PaymentResponse"> | ||
<h3> | ||
POSTing payment response back to a server | ||
|
@@ -1713,6 +1746,7 @@ <h2> | |
dictionary PaymentDetailsUpdate : PaymentDetailsBase { | ||
DOMString error; | ||
PaymentItem total; | ||
AddressErrorFields shippingAddressErrors; | ||
}; | ||
</pre> | ||
<p> | ||
|
@@ -1756,6 +1790,14 @@ <h2> | |
"PaymentCurrencyAmount.value">value</a> is a negative number. | ||
</p> | ||
</dd> | ||
<dt> | ||
<dfn>shippingAddressErrors</dfn> member | ||
</dt> | ||
<dd> | ||
Represents validation errors with the shipping address that is | ||
associated with the <a data-cite="!DOM#event-target">event | ||
target</a>. | ||
</dd> | ||
</dl> | ||
</section> | ||
</section> | ||
|
@@ -2040,7 +2082,7 @@ <h2> | |
Physical addresses | ||
</h2> | ||
<p> | ||
A <dfn>physical address</dfn> is composed of the following concepts. | ||
A <dfn>physical address</dfn> is composed of the following parts. | ||
</p> | ||
<dl data-sort=""> | ||
<dt> | ||
|
@@ -2704,6 +2746,153 @@ <h2> | |
</dd> | ||
</dl> | ||
</section> | ||
<section data-dfn-for="AddressErrorFields" data-link-for= | ||
"AddressErrorFields"> | ||
<h2> | ||
<dfn>AddressErrorFields</dfn> dictionary | ||
</h2> | ||
<pre class="idl"> | ||
dictionary AddressErrorFields { | ||
DOMString addressLineError; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decided to postfix all these with "Error" in the name, as I felt it made it a little bit more clear when in userland code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The extra "Error" suffix feels redundant me, as it should be implied since these are members of the shippingAddressErrors property. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. depends... the problem I ran into was in destructuring and using object short hands. Also, consider the function validateAddress(address){
// whoops, now "postalCode" has been squatted.
const { postalCode } = address;
const postalCodeError = !isValidPostCode(postCode) ? "Invalid zip code" : undefined;
return { postalCodeError }
}
function collectErrors(response) {
// same problem here!
const { shippingAddress } = response;
const shippingAddressErrors = validateAddress(shippingAddress);
return { shippingAddressErrors }
} And so on... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tend to agree this is redundant. I think you have chosen a code style with a combination of object literal shorthand, destructuring, and redundant variable declarations that makes it extra confusing. But I don't think that's a good reason to verbose-ify the API, personally. I would instead suggest writing your code in a more conventional way, such as function validateAddress(address){
return {
postalCode: !isValidPostalCode(address.postalCode) ? "Invalid zip code" : undefined
};
}
function collectErrors(response) {
return {
shippingAddress: validateAddress(response.shippingAddress)
};
} (basically, don't declare variables you're only going to use once. |
||
DOMString cityError; | ||
DOMString countryError; | ||
DOMString dependentLocalityError; | ||
DOMString languageCodeError; | ||
DOMString organizationError; | ||
DOMString phoneError; | ||
DOMString postalCodeError; | ||
DOMString recipientError; | ||
DOMString regionError; | ||
DOMString regionCodeError; | ||
DOMString sortingCodeError; | ||
}; | ||
</pre> | ||
<p> | ||
The members of the <a>AddressErrorFields</a> dictionary represent | ||
validation errors with specific parts of a <a>physical address</a>. | ||
Each dictionary member has a dual function: firstly, it denotes that | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say "firstly, its presence denotes..." |
||
a particular part of an address is suffering from a validation error. | ||
Secondly, the string value allows the developer to describe the | ||
validation error (and possibly how the end user can fix the error). | ||
</p> | ||
<p class="note"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kept this (languageCodeError) for completeness... but wonder if we should just ditch languageCodeError. 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarified what "this" was above. |
||
Developers need to be aware that users might not have the ability to | ||
fix certain parts of an address. As such, they need to be mindful to | ||
not to ask the user to fix things they might not have control over | ||
(e.g., <a>languageCodeError</a>). | ||
</p> | ||
<dl> | ||
<dt> | ||
<dfn>addressLineError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>address line</a> has a validation error. In the | ||
user agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">addressLine</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>cityError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>city</a> has a validation error. In the user | ||
agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">city</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>countryError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>country</a> has a validation error. In the user | ||
agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">country</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>dependentLocalityError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>dependent locality</a> has a validation error. | ||
In the user agent's UI, this member corresponds to the input field | ||
that provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">dependentLocality</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>languageCodeError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>language code</a> has a validation error. In | ||
the user agent's UI, this member corresponds to the input field | ||
that provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">languageCode</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>organizationError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>organization</a> has a validation error. In the | ||
user agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">organization</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>phoneError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>phone number</a> has a validation error. In the | ||
user agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">phone</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>postalCodeError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>postal code</a> has a validation error. In the | ||
user agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">postalCode</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>recipientError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>recipient</a> has a validation error. In the | ||
user agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">addressLine</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>regionError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the <a>region</a> has a validation error. In the user | ||
agent's UI, this member corresponds to the input field that | ||
provided the <a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">region</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>regionCodeError</dfn> member | ||
</dt> | ||
<dd> | ||
Denotes that the region code representation of the <a>region</a> | ||
has a validation error. In the user agent's UI, this member | ||
corresponds to the input field that provided the | ||
<a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">regionCode</a> attribute's value. | ||
</dd> | ||
<dt> | ||
<dfn>sortingCodeError</dfn> member | ||
</dt> | ||
<dd> | ||
The <a>sorting code</a> has a validation error. In the user agent's | ||
UI, this member corresponds to the input field that provided the | ||
<a>PaymentAddress</a>'s <a data-link-for= | ||
"PaymentAddress">sortingCode</a> attribute's value. | ||
</dd> | ||
</dl> | ||
</section> | ||
<section> | ||
<h2> | ||
Creating a <code>PaymentAddress</code> from user-provided input | ||
|
@@ -3914,21 +4103,37 @@ <h2> | |
</li> | ||
</ol> | ||
</li> | ||
<li>If <var>request</var>.<a>[[\options]]</a>.<a data-lt= | ||
"PaymentOptions.requestShipping">requestShipping</a> is true, | ||
and | ||
<var>request</var>.<a>[[\details]]</a>.<a>shippingOptions</a> | ||
is empty, then the developer has signified that there are no | ||
valid shipping options for the currently-chosen shipping | ||
address (given by <var>request</var>'s <a data-lt= | ||
"PaymentRequest.shippingAddress">shippingAddress</a>). In | ||
this case, the user agent SHOULD display an error indicating | ||
this, and MAY indicate that the currently-chosen shipping | ||
address is invalid in some way. The user agent SHOULD use the | ||
<a data-lt="PaymentDetailsUpdate.error">error</a> member of | ||
<var>details</var>, if it is present, to give more | ||
information about why there are no valid shipping options for | ||
that address. | ||
<li> | ||
<p> | ||
If <var>request</var>.<a>[[\options]]</a>.<a data-lt= | ||
"PaymentOptions.requestShipping">requestShipping</a> is | ||
true, and | ||
<var>request</var>.<a>[[\details]]</a>.<a>shippingOptions</a> | ||
is empty, then the developer has signified that there are | ||
no valid shipping options for the currently-chosen | ||
shipping address (given by <var>request</var>'s | ||
<a data-lt= | ||
"PaymentRequest.shippingAddress">shippingAddress</a>). | ||
</p> | ||
<p> | ||
In this case, the user agent SHOULD display an error | ||
indicating this, and MAY indicate that the | ||
currently-chosen shipping address is invalid in some way. | ||
The user agent SHOULD use the <a data-lt= | ||
"PaymentDetailsUpdate.error">error</a> member of | ||
<var>details</var>, if it is present, to give more | ||
information about why there are no valid shipping options | ||
for that address. | ||
</p> | ||
<p> | ||
Further, if the <a data-lt= | ||
"PaymentDetailsUpdate.shippingAddressErrors">shippingAddressErrors</a> | ||
member is present, the user agent SHOULD display an error | ||
specifically for each erroneous field of the shipping | ||
address. This is done by matching each present member of | ||
the <a>AddressErrorFields</a> to a corresponding input | ||
field in the shown user interface. | ||
</p> | ||
</li> | ||
</ol> | ||
</li> | ||
|
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.
Empty shippingOptions should not be necessary, since not-present gets converted to empty in the processing model, I am pretty sure.
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.
In the "update a PaymentRequest's details algorithm", we do an incremental update to
request
, so:Otherwise, the original shipping options are retained - so the developer needs to be explicitly thrash them.