Skip to content
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

[PART 3] Networking Refactor - Add VaultPaymentTokensAPI #188

Merged
merged 21 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0010733
Remove APIRequest conformance from ClientIDRequest in Demo (#178)
scannillo Aug 10, 2023
4a43375
Remove Eligibility feature (#180)
KunJeongPark Aug 10, 2023
55b6c1b
Remove `prefersEphemeralBrowser` setting from ASWebSession (#181)
scannillo Aug 14, 2023
6e6ee65
Bump version to 0.0.10
paypalsdk Aug 14, 2023
a305fa5
UI for Vault with Purchase (#175)
KunJeongPark Aug 15, 2023
7660350
Vault without Purchase (#172)
KunJeongPark Aug 17, 2023
7cc0981
Merge branch 'main' into networking-refactor-main
scannillo Aug 17, 2023
d7209b9
WIP - Add VaultPPasSAPI.swift
scannillo Aug 17, 2023
f91dd0a
Leave TODOs to fix variable encoding bug
scannillo Aug 17, 2023
bbc3f20
Add x-app-name & origin headers (fixing 401 code); use dictionary ove…
scannillo Aug 23, 2023
be7fac6
Replace [String: Any] dict with Encodable for GraphQLQuery variables …
scannillo Aug 23, 2023
17731ac
Move REST request encoding into APIClient & use Encodable over Data t…
scannillo Aug 23, 2023
e4da648
Merge branch 'networking-refactor' into networking-refactor-main
scannillo Aug 23, 2023
221c627
Cleanup CardClient.swift diff updating from main
scannillo Aug 23, 2023
a87f8f2
PR cleanup
scannillo Aug 23, 2023
185a8de
Add GraphQL parsing capability to HTTPResponseParser
scannillo Aug 23, 2023
f8300bd
Update HTTPResponseParser unit tests
scannillo Aug 23, 2023
85aea43
REmove GraphQLClient unit test file
scannillo Aug 23, 2023
6ed48aa
Remove MockGraphQLClient
scannillo Aug 23, 2023
c2d71e7
PR Feedback - newline each comman in queryString
scannillo Aug 23, 2023
af560e2
Remove PPaaS navigation instruction from GraphQL call; unable to find…
scannillo Aug 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions PayPal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
06CE009926F3D1660000CC46 /* CoreConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CE009826F3D1660000CC46 /* CoreConfig.swift */; };
06CE009B26F3D5A40000CC46 /* CardClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CE009A26F3D5A40000CC46 /* CardClient.swift */; };
3B109B3C2A85CC6200D8135F /* MockCardVaultDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B109B3A2A85B54800D8135F /* MockCardVaultDelegate.swift */; };
3B109B3D2A85D1CA00D8135F /* MockGraphQLClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B109B382A85A9DB00D8135F /* MockGraphQLClient.swift */; };
3B22E8B62A840ECF00962E34 /* CardVaultDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B22E8B52A840ECF00962E34 /* CardVaultDelegate.swift */; };
3B22E8B82A841AEA00962E34 /* CardVaultResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B22E8B72A841AEA00962E34 /* CardVaultResult.swift */; };
3B79E4F72A8503CA00C01D06 /* UpdateSetupTokenQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B79E4F62A8503C900C01D06 /* UpdateSetupTokenQuery.swift */; };
3B79E4F72A8503CA00C01D06 /* UpdateVaultVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B79E4F62A8503C900C01D06 /* UpdateVaultVariables.swift */; };
3B80D50C2A27979000D2EAC4 /* FailingJSONEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B80D50B2A27979000D2EAC4 /* FailingJSONEncoder.swift */; };
3BD82DBB2A835AF900CBE764 /* UpdateSetupTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BD82DBA2A835AF900CBE764 /* UpdateSetupTokenResponse.swift */; };
3BDB34942A80CE6E008100D7 /* CardVaultRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDB34932A80CE6E008100D7 /* CardVaultRequest.swift */; };
Expand Down Expand Up @@ -49,6 +48,7 @@
807D56AE2A869064009E591D /* GraphQLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 807D56AD2A869064009E591D /* GraphQLRequest.swift */; };
807D56B02A869F97009E591D /* GraphQLErrorResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 807D56AF2A869F97009E591D /* GraphQLErrorResponse.swift */; };
808EEA81291321FE001B6765 /* AnalyticsEventRequest_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808EEA80291321FE001B6765 /* AnalyticsEventRequest_Tests.swift */; };
80B8B2FC2A8EBBFD00AB60CD /* VaultPaymentTokensAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80B8B2FB2A8EBBFD00AB60CD /* VaultPaymentTokensAPI.swift */; };
80D0C1382731CC9B00548A3D /* PayPalNativeCheckoutClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE7116152723227200165069 /* PayPalNativeCheckoutClient.swift */; };
80DB2F762980795D00CFB86A /* CorePaymentsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DB2F752980795D00CFB86A /* CorePaymentsError.swift */; };
80DB6F1726B89DC700277E54 /* CorePayments.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80B9F85126B8750000D67843 /* CorePayments.framework */; platformFilter = ios; };
Expand Down Expand Up @@ -146,7 +146,6 @@
CBD6004728D0C24A00C3EFF6 /* MockPayPalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD6004628D0C24900C3EFF6 /* MockPayPalDelegate.swift */; };
E6022E802857C6BE008B0E27 /* GraphQLHTTPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64623222836A69E008AC8E1 /* GraphQLHTTPResponse.swift */; };
E64763712899B60C00074113 /* MockAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64763702899B60C00074113 /* MockAPIClient.swift */; };
E699EC16285A388E0044A753 /* GraphQLClient_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E699EC15285A388E0044A753 /* GraphQLClient_Tests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -205,11 +204,10 @@
06CE009A26F3D5A40000CC46 /* CardClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardClient.swift; sourceTree = "<group>"; };
06CE009F26F3DF100000CC46 /* ConfirmPaymentSourceRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmPaymentSourceRequest.swift; sourceTree = "<group>"; };
06CE00A226F3E32A0000CC46 /* ConfirmPaymentSourceResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmPaymentSourceResponse.swift; sourceTree = "<group>"; };
3B109B382A85A9DB00D8135F /* MockGraphQLClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGraphQLClient.swift; sourceTree = "<group>"; };
3B109B3A2A85B54800D8135F /* MockCardVaultDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCardVaultDelegate.swift; sourceTree = "<group>"; };
3B22E8B52A840ECF00962E34 /* CardVaultDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultDelegate.swift; sourceTree = "<group>"; };
3B22E8B72A841AEA00962E34 /* CardVaultResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultResult.swift; sourceTree = "<group>"; };
3B79E4F62A8503C900C01D06 /* UpdateSetupTokenQuery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateSetupTokenQuery.swift; sourceTree = "<group>"; };
3B79E4F62A8503C900C01D06 /* UpdateVaultVariables.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateVaultVariables.swift; sourceTree = "<group>"; };
3B80D50B2A27979000D2EAC4 /* FailingJSONEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailingJSONEncoder.swift; sourceTree = "<group>"; };
3BD82DBA2A835AF900CBE764 /* UpdateSetupTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateSetupTokenResponse.swift; sourceTree = "<group>"; };
3BDB34932A80CE6E008100D7 /* CardVaultRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardVaultRequest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -237,6 +235,7 @@
807D56AD2A869064009E591D /* GraphQLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLRequest.swift; sourceTree = "<group>"; };
807D56AF2A869F97009E591D /* GraphQLErrorResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLErrorResponse.swift; sourceTree = "<group>"; };
808EEA80291321FE001B6765 /* AnalyticsEventRequest_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventRequest_Tests.swift; sourceTree = "<group>"; };
80B8B2FB2A8EBBFD00AB60CD /* VaultPaymentTokensAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VaultPaymentTokensAPI.swift; sourceTree = "<group>"; };
80B9F85126B8750000D67843 /* CorePayments.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CorePayments.framework; sourceTree = BUILT_PRODUCTS_DIR; };
80DB2F752980795D00CFB86A /* CorePaymentsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorePaymentsError.swift; sourceTree = "<group>"; };
80DB6F0E26B89D9600277E54 /* PayPalNativePayments.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PayPalNativePayments.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -333,7 +332,6 @@
CBD6004628D0C24900C3EFF6 /* MockPayPalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPayPalDelegate.swift; sourceTree = "<group>"; };
E64623222836A69E008AC8E1 /* GraphQLHTTPResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLHTTPResponse.swift; sourceTree = "<group>"; };
E64763702899B60C00074113 /* MockAPIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAPIClient.swift; sourceTree = "<group>"; };
E699EC15285A388E0044A753 /* GraphQLClient_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLClient_Tests.swift; sourceTree = "<group>"; };
OBJ_16 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
"PayPal::PayPalTests::Product" /* PayPalNativeCheckoutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = PayPalNativeCheckoutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -492,7 +490,6 @@
8036C1E0270F9BE700C0F091 /* APIClient_Tests.swift */,
802C4A752945676E00896A5D /* AnalyticsService_Tests.swift */,
8036C1E1270F9BE700C0F091 /* Environment_Tests.swift */,
E699EC15285A388E0044A753 /* GraphQLClient_Tests.swift */,
808EEA80291321FE001B6765 /* AnalyticsEventRequest_Tests.swift */,
80FC261C29847AC7008EC841 /* HTTP_Tests.swift */,
807BF5902A2A5D48002F32B3 /* HTTPResponseParser_Tests.swift */,
Expand Down Expand Up @@ -546,11 +543,12 @@
80DBC9D829C336D500462539 /* APIRequests */ = {
isa = PBXGroup;
children = (
3B79E4F62A8503C900C01D06 /* UpdateSetupTokenQuery.swift */,
3B79E4F62A8503C900C01D06 /* UpdateVaultVariables.swift */,
06CE009F26F3DF100000CC46 /* ConfirmPaymentSourceRequest.swift */,
06CE00A226F3E32A0000CC46 /* ConfirmPaymentSourceResponse.swift */,
80E2FDBD2A83528B0045593D /* CheckoutOrdersAPI.swift */,
3BD82DBA2A835AF900CBE764 /* UpdateSetupTokenResponse.swift */,
80B8B2FB2A8EBBFD00AB60CD /* VaultPaymentTokensAPI.swift */,
);
path = APIRequests;
sourceTree = "<group>";
Expand Down Expand Up @@ -591,7 +589,6 @@
065A4DC226FCE1D20007014A /* ConfirmPaymentSourceRequest_Tests.swift */,
CB16E6D7285B7A2B00FD6F52 /* CardResponses.swift */,
CB16E6D9285B7B7300FD6F52 /* MockCardDelegate.swift */,
3B109B382A85A9DB00D8135F /* MockGraphQLClient.swift */,
3B109B3A2A85B54800D8135F /* MockCardVaultDelegate.swift */,
);
path = CardPaymentsTests;
Expand Down Expand Up @@ -1258,7 +1255,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E699EC16285A388E0044A753 /* GraphQLClient_Tests.swift in Sources */,
808EEA81291321FE001B6765 /* AnalyticsEventRequest_Tests.swift in Sources */,
8036C1E5270F9BE700C0F091 /* Environment_Tests.swift in Sources */,
80FC261D29847AC7008EC841 /* HTTP_Tests.swift in Sources */,
Expand Down Expand Up @@ -1340,9 +1336,8 @@
files = (
06CE009B26F3D5A40000CC46 /* CardClient.swift in Sources */,
80E2FDBE2A83528B0045593D /* CheckoutOrdersAPI.swift in Sources */,
3B79E4F72A8503CA00C01D06 /* UpdateSetupTokenQuery.swift in Sources */,
3B79E4F72A8503CA00C01D06 /* UpdateVaultVariables.swift in Sources */,
8048D28C270B9DE00072214A /* ConfirmPaymentSourceResponse.swift in Sources */,
3B109B3D2A85D1CA00D8135F /* MockGraphQLClient.swift in Sources */,
3D1763A22720722A00652E1C /* CardResult.swift in Sources */,
BC0A82A5270B9533006E9A21 /* ConfirmPaymentSourceRequest.swift in Sources */,
CB4BE2802847F01000EA2DD1 /* CardDelegate.swift in Sources */,
Expand All @@ -1353,6 +1348,7 @@
80DCC59E2719DB6F00EC7C5A /* CardClientError.swift in Sources */,
3B22E8B62A840ECF00962E34 /* CardVaultDelegate.swift in Sources */,
3BDB34942A80CE6E008100D7 /* CardVaultRequest.swift in Sources */,
80B8B2FC2A8EBBFD00AB60CD /* VaultPaymentTokensAPI.swift in Sources */,
CB4BE27D2847AF6F00EA2DD1 /* SCA.swift in Sources */,
0647E70E2714962800F8E517 /* Address.swift in Sources */,
BC7F8123275FC1350011EDC8 /* CardRequest.swift in Sources */,
Expand Down
11 changes: 3 additions & 8 deletions Sources/CardPayments/APIRequests/CheckoutOrdersAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,19 @@ class CheckoutOrdersAPI {

// MARK: - Internal Methods

func confirmPaymentSource(clientID: String, cardRequest: CardRequest) async throws -> ConfirmPaymentSourceResponse {
func confirmPaymentSource(cardRequest: CardRequest) async throws -> ConfirmPaymentSourceResponse {
let apiClient = APIClient(coreConfig: coreConfig)

let confirmData = ConfirmPaymentSourceRequest(cardRequest: cardRequest)

// TODO: - Move JSON encoding into custom class, similar to HTTPResponseParser
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let body = try encoder.encode(confirmData)

let restRequest = RESTRequest(
path: "/v2/checkout/orders/\(cardRequest.orderID)/confirm-payment-source",
method: .post,
queryParameters: nil,
body: body
postParameters: confirmData
)

let httpResponse = try await apiClient.fetch(request: restRequest)
return try HTTPResponseParser().parse(httpResponse, as: ConfirmPaymentSourceResponse.self)
return try HTTPResponseParser().parseREST(httpResponse, as: ConfirmPaymentSourceResponse.self)
}
}
83 changes: 0 additions & 83 deletions Sources/CardPayments/APIRequests/UpdateSetupTokenQuery.swift

This file was deleted.

51 changes: 51 additions & 0 deletions Sources/CardPayments/APIRequests/UpdateVaultVariables.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Foundation

struct UpdateVaultVariables: Encodable {

// MARK: - Coding Keys

private enum TopLevelKeys: String, CodingKey {
case clientID
case vaultSetupToken
case paymentSource
}

private enum PaymentSourceKeys: String, CodingKey {
case card
}

private enum CardKeys: String, CodingKey {
case number
case securityCode
case expiry
case name
}

// MARK: - Private Properties

private let vaultRequest: CardVaultRequest
private let clientID: String

// MARK: - Initializer

init(cardVaultRequest: CardVaultRequest, clientID: String) {
self.vaultRequest = cardVaultRequest
self.clientID = clientID
}

// MARK: - Custom Encoder

func encode(to encoder: Encoder) throws {
var topLevel = encoder.container(keyedBy: TopLevelKeys.self)
try topLevel.encode(clientID, forKey: .clientID)
try topLevel.encode(vaultRequest.setupTokenID, forKey: .vaultSetupToken)

var paymentSource = topLevel.nestedContainer(keyedBy: PaymentSourceKeys.self, forKey: .paymentSource)

var card = paymentSource.nestedContainer(keyedBy: CardKeys.self, forKey: .card)
try card.encode(vaultRequest.card.number, forKey: .number)
try card.encode(vaultRequest.card.securityCode, forKey: .securityCode)
try card.encode(vaultRequest.card.expiry, forKey: .expiry)
try card.encodeIfPresent(vaultRequest.card.cardholderName, forKey: .name)
}
}
58 changes: 58 additions & 0 deletions Sources/CardPayments/APIRequests/VaultPaymentTokensAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Foundation
#if canImport(CorePayments)
import CorePayments
#endif

/// This class coordinates networking logic for communicating with the /graphql?UpdateVaultSetupToken API.
///
/// Details on this PayPal API can be found in PPaaS under Merchant > Data Vault > Payment Method Tokens > v3.
class VaultPaymentTokensAPI {

// MARK: - Private Propertires

private let coreConfig: CoreConfig

// MARK: - Initializer

init(coreConfig: CoreConfig) {
self.coreConfig = coreConfig
}

// MARK: - Internal Methods

func updateSetupToken(cardVaultRequest: CardVaultRequest) async throws -> UpdateSetupTokenResponse {
let apiClient = APIClient(coreConfig: coreConfig)

let queryString = """
mutation UpdateVaultSetupToken(
$clientID: String!,
$vaultSetupToken: String!,
$paymentSource: PaymentSource
) {
updateVaultSetupToken(
clientId: $clientID
vaultSetupToken: $vaultSetupToken
paymentSource: $paymentSource
) {
id,
status,
links {
rel, href
scannillo marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
"""

let variables = UpdateVaultVariables(cardVaultRequest: cardVaultRequest, clientID: coreConfig.clientID)

let graphQLRequest = GraphQLRequest(
query: queryString,
variables: variables,
queryNameForURL: "UpdateVaultSetupToken"
)

let httpResponse = try await apiClient.fetch(request: graphQLRequest)

return try HTTPResponseParser().parseGraphQL(httpResponse, as: UpdateSetupTokenResponse.self)
}
}
Loading