-
-
Notifications
You must be signed in to change notification settings - Fork 762
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
Apple Pay - Donate form API calls #4619
Conversation
+ plus rename URL extension file
…ncementsContentSource
980e910
to
f5fce65
Compare
f5fce65
to
b018187
Compare
b018187
to
b3aea1b
Compare
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.
There's a big chunk of work to review here. Here's just very superficial stuff from my first pass. Will dig deeper in next pass.
import Foundation | ||
|
||
extension Int { | ||
var isHttpSuccess: Bool { |
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.
I like the intention, and appreciate it only internal to WKData
, but I wonder if this really needs to extend all Int
s over just being in some generalized HTTP status code utility.
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.
Good idea - I moved this into a HTTPURLResponse
extension.
var components = URLComponents() | ||
components.scheme = "https" | ||
components.path = "/w/api.php" |
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.
Would it make sense to generalize out these repeated constructions into a WMFAPIPath
-ish from NSURL+WMFLinkParsing
thing (BaseMediaWikiAPIPathComponents
?)?
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.
Done (I think) - let me know if it's what you had in mind!
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.
To clarify, I think even pulling the repeated scheme would be useful. Like:
private static var baseMediaWikiAPIPathComponents: URLComponents {
var components = URLComponents()
components.scheme = "https"
components.path = "/w/api.php"
return components
}
static func mediaWikiAPIURL(project: WKProject) -> URL? {
var components = baseMediaWikiAPIPathComponents
switch project {
...
}
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.
Sorry I missed this one - will make a note to put it in a later PR. Thanks!
public let currencyMinimums: [String: Decimal] | ||
public let currencyMaximums: [String: Decimal] | ||
public let currencyAmounts7: [String: [Decimal]] |
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.
I understand these currently match the API, but just wanted to mention the same note as in Slack about potentially more precise naming here if those suggestions still agree with you.
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.
Done! I updated the mock json and the config at donate.wikimedia.org...so far I haven't changed the config at test.wikipedia.org. I will EOD today once I know FR Tech isn't testing against it.
let response: Response | ||
} | ||
|
||
/// {"response":{"status":"Success","gateway_transaction_id":"PVLSL6JZ4NK2WN82","order_id":"1235.1"}} |
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.
Extraneous
import Foundation | ||
|
||
/// Use this service for the most basic networking service calls. It does not handle authentication. | ||
/// |
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.
Extraneous
WMF Framework/FeatureFlags.swift
Outdated
@@ -10,4 +10,11 @@ public struct FeatureFlags { | |||
return true | |||
} | |||
|
|||
public static var applePayEnabled: Bool { |
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.
Minor, but what do you think about something like applePayDonationEnabled
instead? On first read applePayEnabled
connoted the availability of Apple Pay itself to me, rather than our intent of Apple Pay as a donation option.
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.
Done (twice actually, sorry). I went with the more general donorExperienceImrovementsEnabled
- I'm hoping to be able to wrap up all of our improvements in the next few weeks around that for easy rollback, not just the native form.
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.
👍🏽 new name works great, much more precise about what it is
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.
@tonisevener More notes below
switch result { | ||
case .success(let response): | ||
guard response.response.status == "Success" else { | ||
return |
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.
Missing a completion
handler call in this failure case.
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.
Great catch! Done.
guard | ||
let encodedName = key.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryComponentAllowed), | ||
let encodedValue = (value as? String)?.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryComponentAllowed) else { | ||
continue |
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.
Unsure if we want to continue our pattern of assert(...)
in the new frameworks, but this may be a good candidate. Any key/value parameter pair failing to be properly URL encoded means the entire parameter dictionary is invalid, right?
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.
Fixed!
import Foundation | ||
|
||
public protocol WKURLSession { | ||
func wkDataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> WKURLSessionDataTask |
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.
My limited understanding of some of the new Swift concurrency changes (actors/actor isolation/et al) makes it unclear to me if the @Sendable
here and elsewhere is needed or not.
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.
Yeah - I am also unsure if it's entirely necessary. Since WKURLSession is meant to be a basic wrapper for easier unit testing (in WKBasicServiceTests.swift
), it felt correct to directly match the signature of the URLSession method it wraps:
open func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
I'm open to alternative ways to mock this if it feels icky. This workaround came after first trying to mock via a URLSession subclass, and these types of warnings appeared - https://stackoverflow.com/questions/74406895/subclassing-urlsession-init-was-deprecated-in-ios-13-0.
import Foundation | ||
|
||
/// Use this service for the most basic networking service calls. It does not handle authentication. | ||
public final class WKBasicService: WKService { |
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.
Are you intending WKService
to serve some more general purpose than effectively performing network requests? If not, WKNetworkService
, WKBasicNetworkService
, and WKNetworkServiceEnvironment
read as far more precise type identifiers to me.
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.
Nope, only for performing network requests. Back when I worked on wikimedia/wikipedia-ios-data#6 I was hoping that "service" would become synonymous with a class that does networking (i.e. deals with a UrlSession internally) in our minds. I felt like adding "network" in the name might feel redundant or suggest that there are other types of services that do not involve networking. Not a big deal to me though, I've been in the weeds on these classes so far so if the name change makes more sense to fresh eyes I'm happy to change it. Do you think I should add it to other related structs/enums as well? (WKMediaWikiNetworkServiceRequest
, WKNetworkServiceRequestMethod
, etc?)
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.
I can certainly appreciate the desire to keep it short (WKService
over WKNetworkService
) but from my first read of this work it didn't quite click for me. I think I mentally expect Service
as something more generalized, and there being specializations of it – like what if there's some local data service, or some string localization service? That's just my personal take!
For time sake let's leave this as-is and pick this conversation back up in the future as WKData
expands in functionality – sound good?
import Foundation | ||
|
||
/// Use this service for the most basic networking service calls. It does not handle authentication. | ||
public final class WKBasicService: WKService { |
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.
I can certainly appreciate the desire to keep it short (WKService
over WKNetworkService
) but from my first read of this work it didn't quite click for me. I think I mentally expect Service
as something more generalized, and there being specializations of it – like what if there's some local data service, or some string localization service? That's just my personal take!
For time sake let's leave this as-is and pick this conversation back up in the future as WKData
expands in functionality – sound good?
Phabricator:
https://phabricator.wikimedia.org/T345847
Notes
This PR adds the ability to do a few API calls for the donate form:
Since these are pretty basic calls*, I thought this was a good chance to spin up a new service in
WKData
and avoid the loop back to the app for networking. This new service is calledWKBasicService
.*FR Tech endpoints may eventually need an API key, but I don't have those details yet.
I am also fetching the config and payment methods endpoints at the same time as our current announcements endpoint fetch. I may modify it slightly in the future to trigger once our future campaign config call goes through, to reduce unnecessary calls.
Note: b3aea1b will come in handy while the FR Tech endpoints are still in development. So no need to revert before merging, but the goal is to eventually revert this commit.
Test Steps