[w3c/payment-request] Make "total" and "details" optional (#912)

### TL;DR
Given that when [Digital Product Management API](https://discourse.wicg.io/t/proposal-web-payments-digital-product-management-api/4350) is used with PaymentRequest API, the total amount is unnecessary, we propose to make the “total” field optional in PaymentRequest API spec, along with a few consequent changes.

### Make “total” optional
The current PaymentRequest API requires the “total” field (of PaymentDetailsInit) to be mandatory, because any payment must come with a total amount. The mandatory “total” field was reasonable when we assume that developers could specify the “total” only with this field. But this assumption is invalid when the PaymentRequest API is used in conjunction with [the proposed Digital Product Management (DPM) API](https://discourse.wicg.io/t/proposal-web-payments-digital-product-management-api/4350), which connects with the digital store backend where the goods (with product ID) and their prices are specified. With the DPM API, merchants could simply provide the product ID in the PaymentRequest without knowing the total amount. Therefore, we propose to make the “total” field optional in the PaymentRequest API.
### Make “details” optional
After “total” becomes optional, required by [the WebIdl spec](https://heycam.github.io/webidl/#idl-operations), the “details” field would have to become optional with a default value:

> "If the type of an argument is a dictionary type or a union type that has a dictionary type as one of its flattened member types, and that dictionary type and its ancestors have no required members, and the argument is either the final argument or is followed only by optional arguments, then the argument must be specified as optional and have a default value provided."

So we propose “details” should become optional and default to “{}”.
### Improved developer ergonomics
These changes would improve the developer ergonomics, as developers would be able to write:
`new PaymentRequest([{supportedMethods: methodName, data: {productId: ‘abc’}}]);`
instead of:
`new PaymentRequest([{supportedMethods: methodName, data: {productId: ‘abc’}], {total: {...}});`
### Asynchronously fail a request missing required “total”
In cases where “total” is required but missing, we propose that canMakePayment(), hasEnrolledInstrument() and show() should return a promise rejected with a "NotAllowedError" DOMException. Before the proposal, missing “total” would cause a TypeError “Missing required member(s): total” in PaymentRequest’s constructor synchronously. Note that after the proposal the failure would become asynchronous.

Why not fail a missing “total” in the constructor any more? Although it’s good for backwards compatibility, we move away from constructor because:
- only WebIDL type errors should be thrown in the constructor
- canMakePayment, hasEnrolledInstrument, and show are asynchronous methods that may communicate to the payment handler that may require total, so they are more appropriate for the failure.

This change of failure may break the usages of PaymentRequest API that handle TypeError for a missing total. But we deem this breakage as trivial because it’s an error-handling for a programming error -  the merchants should have always provided “total” instead of relying on the TypeError.

### Summary
In summary, we propose these changes to the PaymentRequest API spec:

- make “total” an optional field in PaymentDetailsInit (see the table below).
- make “details” an optional field that is default to {} in PaymentRequest’s constructor (see the table below).
- when missing “total” where it’s required, canMakePayment(), hasEnrolledInstrument() and show() should return a promise rejected with a "NotAllowedError" DOMException.

<table>
<thead><tr><th>Change</th><th>IDL</th></tr></thead>
<tbody>
    <tr>
        <td>Remove “required” from the “total” field</td>
        <td>
<pre><code>
dictionary PaymentDetailsInit : PaymentDetailsBase {
  DOMString id;
  <del>required</del> PaymentItem total;
};</code></pre>
        </td>
    </tr>
    <tr>
        <td>Add “optional” to “details”, and give it a default value {}</td>
        <td>
<pre><code>
[SecureContext, Exposed=Window]
interface PaymentRequest : EventTarget {
  constructor(
    sequence<PaymentMethodData> methodData,
    <ins>optional</ins> PaymentDetailsInit details <ins>= {}</ins>,
    optional PaymentOptions options = {}
  );
  ...
}; 
</code></pre>
        </td>
    </tr>
</tbody>
</table>

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/payment-request/issues/912

Received on Monday, 4 May 2020 18:32:35 UTC