-
Notifications
You must be signed in to change notification settings - Fork 30
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 2] Networking Refactor - Unify REST
& GraphQL
networking implementation
#182
Changes from 32 commits
3e5785a
dcae37b
5cd493a
93f3ba4
a51ab8b
e5285f7
8e07e5d
c83eb48
55f71c4
1243524
63cc3f6
0010733
0493841
b5289e3
bc2213b
4a43375
236ee46
c435d0a
94acd26
508b845
3a32628
2023a49
bc00f95
18de290
2365fc5
2d1bcc0
4abe12e
0695f72
2d5a36a
4ef956b
d3fe188
ff3ed9b
7afefa2
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 | ||
---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||
import Foundation | ||||
|
||||
// TODO: - Rename to `NetworkingClient`. Now that we have `<PPaaS>API.swift` classes, ths responsibility of this class really is to coordinate networking. It transforms REST & GraphQL into HTTP requests. | ||||
/// :nodoc: This method is exposed for internal PayPal use only. Do not use. It is not covered by Semantic Versioning and may change or be removed at any time. | ||||
/// | ||||
/// `APIClient` is the entry point for each payment method feature to perform API requests. It also offers convenience methods for API requests used across multiple payment methods / modules. | ||||
|
@@ -29,7 +30,7 @@ public class APIClient { | |||
|
||||
/// :nodoc: | ||||
public func fetch(request: RESTRequest) async throws -> HTTPResponse { | ||||
let url = try constructURL(path: request.path, queryParameters: request.queryParameters ?? [:]) | ||||
let url = try constructRESTURL(path: request.path, queryParameters: request.queryParameters ?? [:]) | ||||
|
||||
let base64EncodedCredentials = Data(coreConfig.clientID.appending(":").utf8).base64EncodedString() | ||||
|
||||
|
@@ -41,22 +42,26 @@ public class APIClient { | |||
headers[.contentType] = "application/json" | ||||
} | ||||
|
||||
let httpRequest = HTTPRequest( | ||||
headers: headers, | ||||
method: request.method, | ||||
url: url, | ||||
body: request.body | ||||
) | ||||
let httpRequest = HTTPRequest(headers: headers, method: request.method, url: url, body: request.body) | ||||
|
||||
return try await http.performRequest(httpRequest) | ||||
} | ||||
|
||||
// TODO: - Add GraphQL equivalent request type & function | ||||
// public func fetch(request: GraphQLRequest) async throws -> HTTPResponse { } | ||||
/// :nodoc: | ||||
public func fetch(request: GraphQLRequest) async throws -> HTTPResponse { | ||||
let url = try constructGraphQLURL(queryName: request.queryNameForURL) | ||||
|
||||
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. not sure if we need this extra space but up to you:
Suggested change
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 did it intentionally to group |
||||
let postBody = GraphQLHTTPPostBody(query: request.query, variables: request.variables) | ||||
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. 👏🏼 |
||||
let postData = try JSONEncoder().encode(postBody) | ||||
|
||||
let httpRequest = HTTPRequest(headers: [.contentType: "application/json"], method: .post, url: url, body: postData) | ||||
|
||||
return try await http.performRequest(httpRequest) | ||||
} | ||||
|
||||
// MARK: - Private Methods | ||||
|
||||
private func constructURL(path: String, queryParameters: [String: String]) throws -> URL { | ||||
private func constructRESTURL(path: String, queryParameters: [String: String]) throws -> URL { | ||||
let urlString = coreConfig.environment.baseURL.appendingPathComponent(path) | ||||
var urlComponents = URLComponents(url: urlString, resolvingAgainstBaseURL: false) | ||||
|
||||
|
@@ -70,4 +75,16 @@ public class APIClient { | |||
|
||||
return url | ||||
} | ||||
|
||||
private func constructGraphQLURL(queryName: String? = nil) throws -> URL { | ||||
guard let queryName else { | ||||
return coreConfig.environment.graphQLURL | ||||
} | ||||
|
||||
guard let url = URL(string: coreConfig.environment.graphQLURL.absoluteString + "?" + queryName) else { | ||||
throw CorePaymentsError.urlEncodingFailed | ||||
} | ||||
|
||||
return url | ||||
} | ||||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import Foundation | ||
|
||
/// Used to parse error message details out of GraphQL HTTP response body | ||
struct GraphQLErrorResponse: Decodable { | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case error = "error" | ||
case correlationID = "correlation_id" | ||
} | ||
|
||
let error: String | ||
let correlationID: String? | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import Foundation | ||
|
||
/// The GraphQL query and variable details encoded to be sent in the POST body of a HTTP request | ||
struct GraphQLHTTPPostBody: Encodable { | ||
|
||
let query: String | ||
let variables: Data | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/// Used to decode the HTTP reponse body of GraphQL requests | ||
struct GraphQLHTTPResponse<T: Codable>: Codable { | ||
|
||
let data: T? | ||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import Foundation | ||
|
||
/// :nodoc: Values needed to initiate a GraphQL network request | ||
public struct GraphQLRequest { | ||
|
||
let query: String | ||
let variables: Data | ||
|
||
/// This is non-standard in the GraphQL language, but sometimes required by PayPal's GraphQL API. | ||
/// Some requests are sent to `https://www.api.paypal.com/graphql?<queryNameForURL>` | ||
let queryNameForURL: String? | ||
} |
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.
Very cool!