-
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
Use navigator.payments singleton, factory method, or PaymentRequest constructor #16
Comments
In TAG review @triblondon said:
|
@msporny said:
|
Part of the problem with using the constructor is that we have no namespaced place to hang other API methods that we are still working on for things like registration, getting the PaymentRequest and submitting the PaymentResponse as a web based payment app. A factory pattern might be a good compromise? ProposalPut the Sample javascript: var payment = navigator.payments.newPaymentRequest(supportedMethods, details, options, data);
payment.addEventListener("shippingaddresschange", function (changeEvent) {
// Process shipping address change
});
payment.show().then(function(paymentResponse) {
// Process paymentResponse
// paymentResponse.methodName contains the selected payment method
// paymentResponse.details contains a payment method specific response
paymentResponse.complete(true);
}).catch(function(err) {
console.error("Uh oh, something bad happened", err.message);
}); |
Couldn't you use static methods of the |
Finding out what the recommended best practices are for details like this is a big part of the motivation of asking for close review from the TAG. But if the answer really is that there really is no consensus or consistency in this particular case, then that actually is also useful to know. |
It would be worth raising this as a specific question on the TAG mailing
list to get a broader opinion from the whole group.
|
This (interface singleton w/ factory methods) is exactly what the Web Payments Community Group spec proposal does, partly for the reasons outlined by @adrianhopebailie: http://wicg.github.io/web-payments-browser-api/#navigatorpayment and http://wicg.github.io/web-payments-browser-api/#processing-a-payment-request So, +1 for this design direction. If folks want to -1 this, then I'd be interested in hearing where we're going to put methods to do registration, receipt storage (potential future feature), pickup of pending payee-initiated payment requests on the payment app side, etc. |
Are you suggesting a style like this: var thing = PaymentRequest.someMethod(); My only reservation is that I'm certainly more familiar with (and prefer) the pattern: var thing = navigator.payments.someMethod();
var paymentRequest = navigator.payments.createRequest(); I can also imagine us having API endpoints like the following that are used by web-based payment apps: //After the payment app loads ask the browser for the current request that it must process
var paymentRequest = navigator.payments.getRequest();
//Submit back the response
paymentRequest.submitResponse(paymentResponse); Or, if the request is passed to the app as an HTTP request then: //Submit back the response
navigator.payments.submitResponse(paymentResponse); |
Here are my thoughts on this issue. I interpret singleton in this context to mean that we use the same object for each payment request. This would mean that, if The problem with this pattern is that you have to understand how to reset a payment request. Currently the PaymentRequest object is a one-time deal. The state transitions show that you end up in closed and there are no state transitions leading back to earlier states. Reusing objects for new requests has been a source of interop problems in the past (e.g., with XHR) and we should keep this simple and avoid object reuse. This means we should not have a singleton for a payment request. I can live with a factory method if that is really what people want. This could be For our API, the constructor simply validates its arguments. It creates an instance with the validated arguments. It seems fine to use a constructor in this way. There are plenty of types in the browser type system that use constructors today and we've been moving away from unnecessary factory patterns in recent times (e.g. Events). This was the reason we moved to a constructor in the original proposal. I would object to using a singleton but otherwise we should just decide quickly and make this issue go away. I don't see a need to change but if there is a quick consensus to do something else then we should do that now. Otherwise this is just bikeshedding and adding uncertainty to implementation. |
I also like the idea of keeping new classes out of the global namespace (but this is not specific to factory methods). |
How do you keep interfaces out of the global namespace? |
https://dev.w3.org/geo/api/spec-source.html#geolocation_interface
|
@dlongley That's a singleton. |
I think we're going to need to use the interface object for feature detection so we need to include it in the type system. |
We can make https://w3c.github.io/webappsec-credential-management/#interfaces-credential-manager And then add a |
If you're adding |
While more of s style argument I do think there is value in Assuming we may have others like It's a personal preference and I'm open to being persuaded this is old-fashioned |
Upon re-reading all the threads, I don't think anyone proposed a singleton object with shared internal state as a solution? So, I see no support for that, which is good, because I think we're all in agreement on that point. I think what's being proposed is this general shape: navigator.payment Proposalpartial interface Navigator {
readonly attribute PaymentsInterface payment;
};
interface PaymentsInterface {
Promise<PaymentResponse> request(..., options); // this is used by a merchant
Promise<PaymentRequest> getPendingRequest(); // this is used by a payment app
}; Example usageTo create a payment request, you do this: var pr = navigator.payment.request(...); instead of this: var pr = new PaymentRequest(...); Not much difference here, other than how much one has to type. So, let's keep looking for some other usages of the API, like getting pending requests (something a 3rd party Payment App would have to do): // the payment app will need to make this call when it is invoked
var pr = navigator.payment.getPendingRequest(); It's true that we could do it like this: // the payment app will need to make this call when it is invoked
var pr = PaymentRequest.getPendingRequests(); Again, we could do it either way, no strong argument for one over the other yet. Now let's add a feature that doesn't really have to do with Payment Requests but does have to do with the payments ecosystem: var reg = navigator.payment.registerApp(...); and this is how this might be handled with the current spec approach: var reg = PaymentRequest.registerApp(...); Now it starts getting a bit strange. Why are we calling the app registration method on PaymentRequest? What does registration have to do with the PaymentRequest interface? This same argument will come up if/when we add any functionality that has a tenuous connection to PaymentRequest. For example, how do we initiate the storage of digital receipts? var save = PaymentRequest.storeReceipt(...); At this point, PaymentRequest stops being just about payment requests and is instead starting to be used as "the Payment Request API static object". To put it another way, we have two things that we're talking about here:
The current specification attempts to shove both items above into PaymentRequest and that seems like a bad thing to do from a design perspective because it turns something that's meant to be a fairly clean and simple interface (PaymentRequest) into a grab bag of functionality (everything that you can do in the Web Payments ecosystem). So, by using the proposal above, it will help organize methods mostly unrelated to PaymentRequests under an easily understandable namespace 'navigator.payment.' |
As we evolve the API in what way? Can you give some examples of what you'd like to query for (including non-binary checks)? I'm also not convinced that it would be a good thing to have to interrogate an interface for things like 'requestPayerEmail'. In the future would I be checking for What other examples of feature detection are you referring to? It would be easier to respond if we can ground this in some concrete examples. |
+1 to @adrianhopebailie on namespacing under var request = navigator.payments.request(supportedMethods, paymentDetails);
request.addEventListener("eventname", e => {/*....*/));
request.show().then(instrumentResponse => {/*....*/}).catch(error => {/*....*/}); Then we can place new methods (e.g., registration) under the navigator.payments.register(appData); |
+1 to avoid singletons as well. I realize that |
I've spent some time trying to change the proposals here into a pull request that I can live with but after looking at a couple of options I'm not currently a supporter of this change. One goal of the current design is that using the constructor signifies lightweight object creation with no processing other than synchronous validation of the arguments. This means you can construct a Calling I toyed with the idea of using We have lots of constructors in our type system today. Fairly recently, Events moved away from using the With this in mind I propose that we keep the current API, at least for now until we learn more. |
@adrianba - This makes sense to me, I am happy to leave this as is. |
This issue comes from WICG/paymentrequest#42.
From the spec:
The text was updated successfully, but these errors were encountered: