diff --git a/Sources/PayPal/API/Controller.swift b/Sources/PayPal/API/Controller.swift index 0df0a72b..eae80394 100644 --- a/Sources/PayPal/API/Controller.swift +++ b/Sources/PayPal/API/Controller.swift @@ -9,6 +9,11 @@ public protocol PayPalController: ServiceType { /// The API resource that the controller connects to. var resource: String { get } + /// The version of the PayPal API to use when making request's to the API. + /// + /// Defaults to `.v1`. + var version: Version { get } + /// Creates an instance of the controller on a given container. /// /// Instead of directly initializing the controller, you should register @@ -16,11 +21,6 @@ public protocol PayPalController: ServiceType { /// /// - Parameter container: The container that the controller belongs to. init(container: Container) - - /// The controller's path used on the PayPal API. - /// - /// The default value is `v{Configuration.version}/{resource}/`. - func path()throws -> String } extension PayPalController { @@ -31,10 +31,22 @@ extension PayPalController { } /// The controller's path used on the PayPal API. + public var path: String { + return "v" + self.version.rawValue + "/" + resource + "/" + } + + /// Fetches the registered `PayPalClient` instance from the container and makes it + /// availible in a closure, so any errors that are thrown can be caught and returned in the resulting future. + /// + /// - Parameter closure: The closure you have access to the `PayPalClient` in. /// - /// The default value is `v{Configuration.version}/{resource}/`. - public func path()throws -> String { - let config = try self.container.make(Configuration.self) - return "v" + config.version + "/" + resource + "/" + /// - Returns: The future returned from the closure passed in. + public func client(_ closure: (PayPalClient)throws -> (Future)) -> Future { + do { + let client = try self.container.make(PayPalClient.self) + return try closure(client) + } catch let error { + return self.container.future(error: error) + } } } diff --git a/Sources/PayPal/API/Controllers/Activities.swift b/Sources/PayPal/API/Controllers/Activities.swift index 13442115..778cbf7d 100644 --- a/Sources/PayPal/API/Controllers/Activities.swift +++ b/Sources/PayPal/API/Controllers/Activities.swift @@ -15,10 +15,14 @@ public final class Activities: PayPalController { /// See `PayPalController.resource`. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "activities" + self.version = try container.make(Configuration.self).version || .v1 } /// Sends a request to the PayPal `GET /v{Configuration.version}/activities/activities` endpoint. @@ -27,10 +31,9 @@ public final class Activities: PayPalController { /// /// - Parameter parameters: The querys string parameters to send in the request URL. /// - Returns: The endpoint's response, decoded to an `ActivitiesResponse` object, wrapped in a future. - public func activities(parameters: QueryParamaters = QueryParamaters()) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + "activities", parameters: parameters) + public func activities(parameters: QueryParamaters = QueryParamaters()) -> Future { + return self.client { client in + return client.get(self.path + "activities", parameters: parameters) } } } diff --git a/Sources/PayPal/API/Controllers/BillingAgreements.swift b/Sources/PayPal/API/Controllers/BillingAgreements.swift index 5a73384d..325d3915 100644 --- a/Sources/PayPal/API/Controllers/BillingAgreements.swift +++ b/Sources/PayPal/API/Controllers/BillingAgreements.swift @@ -21,10 +21,14 @@ public final class BillingAgreements: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "payments//billing-agreements" + self.version = try container.make(Configuration.self).version || .v1 } /// Creates a billing agreement. @@ -39,9 +43,8 @@ public final class BillingAgreements: PayPalController { /// - Returns: The billing agreement that was created, wrapped in a future. If an error occured /// while creating the agreement, that is wrapped in the future instead. public func create(with agreement: NewAgreement) -> Future { - return Future.flatMap(on: container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(), body: agreement, as: BillingAgreement.self) + return self.client { client in + return client.post(self.path, body: agreement, as: BillingAgreement.self) } } @@ -56,9 +59,8 @@ public final class BillingAgreements: PayPalController { /// - Returns: The HTTP status code of the response, which will be 200. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. public func update(agreement id: String, with patches: [Patch]) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.patch(self.path() + id, body: ["patch_request": patches], as: HTTPStatus.self) + return self.client { client in + return client.patch(self.path + id, body: ["patch_request": patches], as: HTTPStatus.self) } } @@ -73,9 +75,8 @@ public final class BillingAgreements: PayPalController { /// If an error is returned in the response, it is converted to a Swift error /// and is tha value that the future wraps instead. public func get(agreement id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + id, as: BillingAgreement.self) + return self.client { client in + return client.get(self.path + id, as: BillingAgreement.self) } } @@ -91,13 +92,11 @@ public final class BillingAgreements: PayPalController { /// - Returns: The HTTP status code of the response, which will be 204. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. public func billBalance(for agreementID: String, reason: String?) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard reason?.count ?? 0 <= 128 else { throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less") } - - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + agreementID + "/bill-balance", body: ["note": reason], as: HTTPStatus.self) + return client.post(self.path + agreementID + "/bill-balance", body: ["note": reason], as: HTTPStatus.self) } } @@ -113,13 +112,11 @@ public final class BillingAgreements: PayPalController { /// - Returns: The HTTP status code of the response, which will be 204. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. public func cancel(agreement id: String, reason: String?) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard reason?.count ?? 0 <= 128 else { throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less") } - - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/cancel", body: ["note": reason], as: HTTPStatus.self) + return client.post(self.path + id + "/cancel", body: ["note": reason], as: HTTPStatus.self) } } @@ -135,13 +132,12 @@ public final class BillingAgreements: PayPalController { /// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. public func reactivate(agreement id: String, reason: String?) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard reason?.count ?? 0 <= 128 else { throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less") } - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/re-activate", body: ["note": reason], as: HTTPStatus.self) + return client.post(self.path + id + "/re-activate", body: ["note": reason], as: HTTPStatus.self) } } @@ -155,10 +151,9 @@ public final class BillingAgreements: PayPalController { /// /// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. - public func setBalance(for agreementID: String, amount: Money) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + agreementID + "/set-balance", body: amount, as: HTTPStatus.self) + public func setBalance(for agreementID: String, amount: CurrencyCodeAmount) -> Future { + return self.client { client in + return client.post(self.path + agreementID + "/set-balance", body: amount, as: HTTPStatus.self) } } @@ -173,13 +168,11 @@ public final class BillingAgreements: PayPalController { /// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the /// response, it will get conveted to a Swift error and be returned in the future instead. public func suspend(agreement id: String, reason: String?) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard reason?.count ?? 0 <= 128 else { throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less") } - - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/suspend", body: ["note": reason], as: HTTPStatus.self) + return client.post(self.path + id + "/suspend", body: ["note": reason], as: HTTPStatus.self) } } @@ -196,9 +189,8 @@ public final class BillingAgreements: PayPalController { /// - Returns: An array of transactions for the billing agreement within the time periods set in the query paramaters. /// If an error was found in the response, it is converted to a Swift error and that is what the future wraps instead. public func transactions(for agreementID: String, parameters: QueryParamaters = QueryParamaters()) -> Future<[Transaction]> { - return Future.flatMap(on: self.container) { () -> Future<[Transaction]> in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + agreementID + "/transactions", parameters: parameters, as: [Transaction].self) + return self.client { client in + return client.get(self.path + agreementID + "/transactions", parameters: parameters, as: [Transaction].self) } } @@ -211,9 +203,8 @@ public final class BillingAgreements: PayPalController { /// - Returns: The billing agreement object that was executed wrapped in a future. /// If an error was found in the response, it is converted to a Swift error and that is what the future wraps instead. public func execute(agreement id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/agreement-execute", as: BillingAgreement.self) + return self.client { client in + return client.post(self.path + id + "/agreement-execute", as: BillingAgreement.self) } } } diff --git a/Sources/PayPal/API/Controllers/BillingPlans.swift b/Sources/PayPal/API/Controllers/BillingPlans.swift index ae990ff4..814dc786 100644 --- a/Sources/PayPal/API/Controllers/BillingPlans.swift +++ b/Sources/PayPal/API/Controllers/BillingPlans.swift @@ -26,10 +26,14 @@ public final class BillingPlans: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "payments/billing-plans" + self.version = try container.make(Configuration.self).version || .v1 } @@ -46,11 +50,9 @@ public final class BillingPlans: PayPalController { /// - Returns: The created billing plan wrapped in a future. If an error response was sent back instead, it gets converted /// to a Swift error and the future wraps that instead. public func create(with plan: BillingPlan) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard plan.type != nil else { throw PayPalError(identifier: "nilValue", reason: "BillingPlan `type` value must not be `nil`.") } - - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(), body: plan, as: BillingPlan.self) + return client.post(self.path, body: plan, as: BillingPlan.self) } } @@ -65,9 +67,8 @@ public final class BillingPlans: PayPalController { /// /// - Returns: A list of the billing plans wrapped in a future. If an error response was sent back instead, it gets converted /// to a Swift error and the future wraps that instead. - public func list(state: BillingPlan.State? = nil, parameters: QueryParamaters = QueryParamaters()) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + public func list(state: BillingPlan.State? = nil, parameters: QueryParamaters = QueryParamaters()) -> Future { + return self.client { client in var params = parameters if let state = state, params.custom == nil { @@ -75,7 +76,7 @@ public final class BillingPlans: PayPalController { } else { params.custom?["status"] = state?.rawValue } - return try client.get(self.path(), parameters: params, as: BillingPlanList.self) + return client.get(self.path, parameters: params, as: BillingPlan.List.self) } } @@ -91,9 +92,8 @@ public final class BillingPlans: PayPalController { /// - Returns: The HTTP status of the response, in this case `200 OK`. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func update(plan id: String, patches: [Patch]) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.patch(self.path() + id, body: patches, as: HTTPStatus.self) + return self.client { client in + return client.patch(self.path + id, body: patches, as: HTTPStatus.self) } } @@ -106,9 +106,8 @@ public final class BillingPlans: PayPalController { /// - Returns: The billing plan for the ID passed in, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func details(plan id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + id, as: BillingPlan.self) + return self.client { client in + return client.get(self.path + id, as: BillingPlan.self) } } @@ -124,8 +123,6 @@ public final class BillingPlans: PayPalController { /// it gets converted to a Swift error and the future wraps that instead. public func setState(of planID: String, to state: BillingPlan.State) -> Future { let newValue = JSON.object(["state": .string(state.rawValue)]) - return self.update(plan: planID, patches: [ - Patch(operation: .replace, path: "/", value: newValue) - ]) + return self.update(plan: planID, patches: [ Patch(operation: .replace, path: "/", value: newValue) ]) } } diff --git a/Sources/PayPal/API/Controllers/CustomerDisputes.swift b/Sources/PayPal/API/Controllers/CustomerDisputes.swift index 6bbcf543..b7627b41 100644 --- a/Sources/PayPal/API/Controllers/CustomerDisputes.swift +++ b/Sources/PayPal/API/Controllers/CustomerDisputes.swift @@ -32,10 +32,14 @@ public final class CustomerDisputes: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "customer/disputes" + self.version = try container.make(Configuration.self).version || .v1 } @@ -71,9 +75,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: A list of customer disputes wrapped in a future. If an error response was sent back instead, it gets converted /// to a Swift error and the future wraps that instead. public func list(parameters: QueryParamaters = QueryParamaters()) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(), parameters: parameters, as: CustomerDisputeList.self) + return self.client { client in + return client.get(self.path, parameters: parameters, as: CustomerDisputeList.self) } } @@ -87,9 +90,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: A customer dispute wrapped in a future. If an error response was sent back instead, it gets converted /// to a Swift error and the future wraps that instead. public func details(for disputeID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + disputeID, as: CustomerDispute.self) + return self.client { client in + return client.get(self.path + disputeID, as: CustomerDispute.self) } } @@ -105,9 +107,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: An array containing a link to the dispute wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func accept(claim disputeID: String, with body: AcceptDisputeBody) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + disputeID + "/accept-claim", body: body, as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + disputeID + "/accept-claim", body: body, as: LinkResponse.self)["links", []] } } @@ -129,9 +130,8 @@ public final class CustomerDisputes: PayPalController { guard try self.container.make(Configuration.self).environment == .sandbox else { throw Abort(.internalServerError, reason: "Dispute settlement endpoint only availible in sandbox environment.") } - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/adjudicate", body: ["adjudication_outcome": outcome], as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + id + "/adjudicate", body: ["adjudication_outcome": outcome], as: LinkResponse.self)["links", []] } } @@ -150,9 +150,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: An array of request-related [HATEOAS links](https://developer.paypal.com/docs/api/overview/#hateoas-links). /// If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func appeal(dispute id: String, evidence: [Evidence]) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/appeal", body: evidence, as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + id + "/appeal", body: evidence, as: LinkResponse.self)["links", []] } } @@ -167,13 +166,11 @@ public final class CustomerDisputes: PayPalController { /// - Returns: An array of request-related [HATEOAS links](https://developer.paypal.com/docs/api/overview/#hateoas-links). /// If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func escalate(dispute id: String, note: String) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in + return self.client { client in guard note.count >= 1 && note.count <= 2000 else { throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length between 0 and 2000") } - - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/escalate", body: ["note": note], as: LinkResponse.self)["links", []] + return client.post(self.path + id + "/escalate", body: ["note": note], as: LinkResponse.self)["links", []] } } @@ -189,9 +186,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: An array of request-related [HATEOAS links](https://developer.paypal.com/docs/api/overview/#hateoas-links). /// If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func offerResolution(for disputeID: String, offer: CustomerDispute.ResolutionOffer) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + disputeID + "/make-offer", body: offer, as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + disputeID + "/make-offer", body: offer, as: LinkResponse.self)["links", []] } } @@ -226,7 +222,7 @@ public final class CustomerDisputes: PayPalController { let json = try MultipartPart(data: JSONEncoder().encode(evidences), headers: ["Content-Type": "application/json"]) let body: [String: MultipartPartConvertible] = ["input": json, "file1": file] - let request: Request = try self.container.paypal(.POST, self.path() + disputeID + "/provide-evidence", body: nil as [Int]?) + let request: Request = try self.container.paypal(.POST, self.path + disputeID + "/provide-evidence", body: nil as [Int]?) try request.content.encode(body.parts(), as: .related) let response = try self.container.client().send(request) @@ -268,9 +264,8 @@ public final class CustomerDisputes: PayPalController { guard try self.container.make(Configuration.self).environment == .sandbox else { throw Abort(.internalServerError, reason: "Dispute settlement endpoint only availible in sandbox environment.") } - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + disputeID + "/require-evidence", body: ["action": action], as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + disputeID + "/require-evidence", body: ["action": action], as: LinkResponse.self)["links", []] } } @@ -285,9 +280,8 @@ public final class CustomerDisputes: PayPalController { /// - Returns: An array of request-related [HATEOAS links](https://developer.paypal.com/docs/api/overview/#hateoas-links). /// If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func message(dispute id: String, content: String) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/send-message", body: ["message": content], as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + id + "/send-message", body: ["message": content], as: LinkResponse.self)["links", []] } } } diff --git a/Sources/PayPal/API/Controllers/Identity.swift b/Sources/PayPal/API/Controllers/Identity.swift index a0f9fa55..7c05ea7e 100644 --- a/Sources/PayPal/API/Controllers/Identity.swift +++ b/Sources/PayPal/API/Controllers/Identity.swift @@ -15,10 +15,14 @@ public final class Identity: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "identity" + self.version = try container.make(Configuration.self).version || .v1 } /// Retrieves the authenticated user's profile attributes. @@ -26,9 +30,8 @@ public final class Identity: PayPalController { /// - Returns: A `UserInfo` object, containing user profile attributes. The attributes returned depend on the scopes configured for the REST app. /// For example, if the `address` scope is not configured for the app, the response does not include the `address` attribute. public func info() -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + "openidconnect/userinfo", parameters: QueryParamaters(custom: ["schema": "openid"]), as: UserInfo.self) + return self.client { client in + return client.get(self.path + "openidconnect/userinfo", parameters: QueryParamaters(custom: ["schema": "openid"]), as: UserInfo.self) } } } diff --git a/Sources/PayPal/API/Controllers/Invoices.swift b/Sources/PayPal/API/Controllers/Invoices.swift index cbb2bf2e..17e15bbc 100644 --- a/Sources/PayPal/API/Controllers/Invoices.swift +++ b/Sources/PayPal/API/Controllers/Invoices.swift @@ -13,10 +13,14 @@ public class Invoices: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public required init(container: Container) { self.container = container self.resource = "invoicing/invoices" + self.version = try container.make(Configuration.self).version || .v1 } /// Creates a draft invoice. To move the invoice from a draft to payable state, @@ -32,9 +36,8 @@ public class Invoices: PayPalController { /// /// - Returns: The saved Invoice. If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func create(invoice: Invoice) -> Future { - return Future.flatMap(on: self.container) { () -> EventLoopFuture in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(), body: invoice, as: Invoice.self) + return self.client { client in + return client.post(self.path, body: invoice, as: Invoice.self) } } @@ -48,9 +51,8 @@ public class Invoices: PayPalController { /// - Returns: The list of invoices that match the query parameters passed in. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func list(parameters: QueryParamaters = QueryParamaters()) -> Future { - return Future.flatMap(on: self.container) { () -> EventLoopFuture in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(), parameters: parameters, as: InvoiceList.self) + return self.client { client in + return client.get(self.path, parameters: parameters, as: InvoiceList.self) } } @@ -65,9 +67,8 @@ public class Invoices: PayPalController { /// /// - Returns: The updated invoice object. If an error response was sent back instead, it gets converted to a Swift error and the future wraps that instead. public func update(invoice id: String, with body: Invoice, notifyMerchant notify: Bool = true) -> Future { - return Future.flatMap(on: self.container) { () -> EventLoopFuture in - let client = try self.container.make(PayPalClient.self) - return try client.put(self.path() + id, parameters: QueryParamaters(custom: ["notify_merchant": notify.description]), body: body, as: Invoice.self) + return self.client { client in + return client.put(self.path + id, parameters: QueryParamaters(custom: ["notify_merchant": notify.description]), body: body, as: Invoice.self) } } @@ -80,9 +81,8 @@ public class Invoices: PayPalController { /// - Returns: The invoice data for the ID passed in. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func details(for invoiceID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + invoiceID, as: Invoice.self) + return self.client { client in + return client.get(self.path + invoiceID, as: Invoice.self) } } @@ -97,9 +97,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 204 (No Content). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func deleteDraft(invoice id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.delete(self.path() + id, as: HTTPStatus.self) + return self.client { client in + return client.delete(self.path + id, as: HTTPStatus.self) } } @@ -112,9 +111,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 204 (No Content). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func cancel(invoice id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/cancel", as: HTTPStatus.self) + return self.client { client in + return client.post(self.path + id + "/cancel", as: HTTPStatus.self) } } @@ -129,9 +127,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 204 (No Content). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func delete(payment: String, forInvoice invoice: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.delete(self.path() + invoice + "/payment-records/" + payment, as: HTTPStatus.self) + return self.client { client in + return client.delete(self.path + invoice + "/payment-records/" + payment, as: HTTPStatus.self) } } @@ -152,15 +149,13 @@ public class Invoices: PayPalController { /// - Returns: The base64-encoded image of the `image/png` type. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func generateQR(for invoiceID: String, width: Int = 500, height: Int = 500) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard (150...500).contains(width) && (150...500).contains(height) else { throw Abort(.internalServerError, reason: "Height and width values for QR code must be between 150 and 500") } - - let client = try self.container.make(PayPalClient.self) let parameters = QueryParamaters(custom: ["width": width.description, "height": height.description]) - return try client.get(self.path() + invoiceID + "/qr-code", parameters: parameters, as: [String: String].self)["image"].unwrap( + return client.get(self.path + invoiceID + "/qr-code", parameters: parameters, as: [String: String].self)["image"].unwrap( or: Abort(.failedDependency, reason: "`image` key not found in PayPal response") ) } @@ -177,9 +172,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 200 (OK). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func pay(invoice id: String, payment: Invoice.Payment) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/record-payment", body: payment, as: HTTPStatus.self) + return self.client { client in + return client.post(self.path + id + "/record-payment", body: payment, as: HTTPStatus.self) } } @@ -194,9 +188,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 200 (OK). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func refund(invoice id: String, payment: Invoice.Payment) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/record-refund", body: payment, as: HTTPStatus.self) + return self.client { client in + return client.post(self.path + id + "/record-refund", body: payment, as: HTTPStatus.self) } } @@ -211,9 +204,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 204 (No Content). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func delete(refund: String, forInvoice invoice: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.delete(self.path() + invoice + "/refund-records/" + refund, as: HTTPStatus.self) + return self.client { client in + return client.delete(self.path + invoice + "/refund-records/" + refund, as: HTTPStatus.self) } } @@ -229,9 +221,8 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 202 (Accepted). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func remind(invoice id: String, with reminder: Invoice.Reminder) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/remind", body: reminder, as: HTTPStatus.self) + return self.client { client in + return client.post(self.path + id + "/remind", body: reminder, as: HTTPStatus.self) } } @@ -250,9 +241,8 @@ public class Invoices: PayPalController { /// - Returns: An array containing a link to the dispute wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func schedule(invoice id: String) -> Future<[LinkDescription]> { - return Future.flatMap(on: self.container) { () -> Future<[LinkDescription]> in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path() + id + "/schedule", as: LinkResponse.self)["links", []] + return self.client { client in + return client.post(self.path + id + "/schedule", as: LinkResponse.self)["links", []] } } @@ -269,11 +259,10 @@ public class Invoices: PayPalController { /// - Returns: The HTTP status of the response, which will be 202 (Accepted). If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func send(invoice id: String, notifyMerchant notify: Bool = true) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + return self.client { client in let parameters = QueryParamaters(custom: ["notify_merchant": notify.description]) - return try client.post(self.path() + id + "/send", parameters: parameters, as: HTTPStatus.self) + return client.post(self.path + id + "/send", parameters: parameters, as: HTTPStatus.self) } } @@ -285,9 +274,8 @@ public class Invoices: PayPalController { /// - Returns: The new invoice number, incremented from the last number. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func nextNumber() -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(), as: [String: String].self)["number"].unwrap( + return self.client { client in + return client.post(self.path, as: [String: String].self)["number"].unwrap( or: Abort(.failedDependency, reason: "`number` key not found in PayPal response") ) } @@ -302,10 +290,9 @@ public class Invoices: PayPalController { /// - Returns: The list of invoices that match the search criteria passed in, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func search(with body: Invoice.Search) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + return self.client { client in let config = try self.container.make(Configuration.self) - let path = "v" + config.version + "/invoicing/search" + let path = "v" + config.version.rawValue + "/invoicing/search" return client.post(path, body: body, as: InvoiceList.self) } diff --git a/Sources/PayPal/API/Controllers/ManagedAccounts.swift b/Sources/PayPal/API/Controllers/ManagedAccounts.swift index 2bfa92a4..c787af67 100644 --- a/Sources/PayPal/API/Controllers/ManagedAccounts.swift +++ b/Sources/PayPal/API/Controllers/ManagedAccounts.swift @@ -27,10 +27,14 @@ public final class ManagedAccounts: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "partners/merchant-accounts" + self.version = try container.make(Configuration.self).version || .v1 } /// Creates a merchant account. Submit the merchant account information in the JSON request body. @@ -42,9 +46,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: Creation success information, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func create(account: MerchantAccount) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(), body: account, as: CreatedMerchantResponse.self) + return self.client { client in + return client.post(self.path, body: account, as: CreatedMerchantResponse.self) } } @@ -61,9 +64,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: The HTTP status code of the response, which will be `204 No Content`. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func patch(account id: String, with patchs: [Patch]) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.patch(self.path() + id, body: ["patch_request": patchs], as: HTTPStatus.self) + return self.client { client in + return client.patch(self.path + id, body: ["patch_request": patchs], as: HTTPStatus.self) } } @@ -78,9 +80,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: The HTTP status code of the response, which will be `204 No Content`. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func update(account id: String, with data: MerchantAccount) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.put(self.path() + id, body: data, as: HTTPStatus.self) + return self.client { client in + return client.put(self.path + id, body: data, as: HTTPStatus.self) } } @@ -93,9 +94,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: The data for the merchant account, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func details(for accountID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + accountID, as: MerchantAccount.self) + return self.client { client in + return client.get(self.path + accountID, as: MerchantAccount.self) } } @@ -108,9 +108,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: The balance of the account of the ID passed in, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func balance(for accountID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + accountID + "/balances", as: BalanceResponse.self) + return self.client { client in + return client.get(self.path + accountID + "/balances", as: BalanceResponse.self) } } @@ -123,9 +122,8 @@ public final class ManagedAccounts: PayPalController { /// - Returns: The details of the account's financial instruments, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func financialInstruments(for accountID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + accountID + "/financial-instruments", as: FinancialInstruments.self) + return self.client { client in + return client.get(self.path + accountID + "/financial-instruments", as: FinancialInstruments.self) } } } diff --git a/Sources/PayPal/API/Controllers/Orders.swift b/Sources/PayPal/API/Controllers/Orders.swift index 43690cc2..750f9134 100644 --- a/Sources/PayPal/API/Controllers/Orders.swift +++ b/Sources/PayPal/API/Controllers/Orders.swift @@ -15,10 +15,14 @@ public final class Orders: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "checkout/orders" + self.version = try container.make(Configuration.self).version || .v1 } /// Creates an order. @@ -33,18 +37,17 @@ public final class Orders: PayPalController { /// - Returns: The new order created by PayPal, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func create(order: Order, partnerID id: String?) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - let headers: HTTPHeaders = id == nil ? [:] : ["PayPal-Partner-Attribution-Id": id!] + return self.client { client in + let headers: HTTPHeaders = id == nil ? [:] : [HTTPHeaderName.paypalAttribution.description: id!] if order.units == nil || order.redirects == nil { var order = order if order.units == nil { order.units = [] } if order.redirects == nil { order.redirects = Redirects(return: nil, cancel: nil) } - return try client.post(self.path(), headers: headers, body: order, as: Order.self) + return client.post(self.path, headers: headers, body: order, as: Order.self) } else { - return try client.post(self.path(), headers: headers, body: order, as: Order.self) + return client.post(self.path, headers: headers, body: order, as: Order.self) } } } @@ -60,9 +63,8 @@ public final class Orders: PayPalController { /// - Returns: An HTTP status, which will be `204 No Content`, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func cancel(order id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.delete(self.path() + id, as: HTTPStatus.self) + return self.client { client in + return client.delete(self.path + id, as: HTTPStatus.self) } } @@ -76,9 +78,8 @@ public final class Orders: PayPalController { /// - Returns: The order for the ID passed in, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func details(for orderID: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path() + orderID, as: Order.self) + return self.client { client in + return client.get(self.path + orderID, as: Order.self) } } @@ -101,18 +102,17 @@ public final class Orders: PayPalController { /// - Returns: The order the payment is made for, wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func pay(order id: String, with body: Order.PaymentRequest, partner partnerID: String? = nil, request requestID: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + return self.client { client in var headers: HTTPHeaders = [:] if let partner = partnerID { - headers.add(name: "PayPal-Partner-Attribution-Id", value: partner) + headers.add(name: .paypalAttribution, value: partner) } if let request = requestID { - headers.add(name: "PayPal-Request-Id", value: request) + headers.add(name: .paypalRequest, value: request) } - return try client.post(self.path() + id + "/pay", headers: headers, body: body, as: Order.self) + return client.post(self.path + id + "/pay", headers: headers, body: body, as: Order.self) } } } diff --git a/Sources/PayPal/API/Controllers/Payments.swift b/Sources/PayPal/API/Controllers/Payments.swift index b6ed6f60..64127abb 100644 --- a/Sources/PayPal/API/Controllers/Payments.swift +++ b/Sources/PayPal/API/Controllers/Payments.swift @@ -53,10 +53,14 @@ public final class Payments: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "payments" + self.version = try container.make(Configuration.self).version || .v1 } // MARK: - /payment @@ -85,11 +89,10 @@ public final class Payments: PayPalController { /// - Returns: The payment that was created, wrapped in a future. If PayPal returns an error response instead, /// it will get converted to a Swift error and the future will wrap that. public func create(payment: Payment, partner: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + return self.client { client in let headers: HTTPHeaders = partner == nil ? [:] : ["PayPal-Partner-Attribution-Id": partner!] - return try client.post(self.path(for: .payment), headers: headers, body: payment, as: Payment.self) + return client.post(self.path(for: .payment), headers: headers, body: payment, as: Payment.self) } } @@ -111,13 +114,11 @@ public final class Payments: PayPalController { /// range of payments and the ID of the element to use to get the next range of results. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func list(parameters: QueryParamaters = QueryParamaters()) -> Future { - return Future.flatMap(on: self.container) { () -> Future in + return self.client { client in guard parameters.count ?? 0 <= 20 else { throw PayPalError(status: .internalServerError, identifier: "invalidCount", reason: "`count` query paramater must be 20 or less") } - - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .payment), parameters: parameters, as: PaymentList.self) + return client.get(self.path(for: .payment), parameters: parameters, as: PaymentList.self) } } @@ -136,9 +137,8 @@ public final class Payments: PayPalController { /// - Returns: The payment that was updated, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func patch(payment id: String, with patches: [Patch]) -> Future { - return Future.flatMap(on: self.container) { () -> EventLoopFuture in - let client = try self.container.make(PayPalClient.self) - return try client.patch(self.path(for: .payment) + id, body: patches, as: Payment.self) + return self.client { client in + return client.patch(self.path(for: .payment) + id, body: patches, as: Payment.self) } } @@ -151,9 +151,8 @@ public final class Payments: PayPalController { /// - Returns: The payment for the ID passed in. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(payment id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .payment) + id, as: Payment.self) + return self.client { client in + return client.get(self.path(for: .payment) + id, as: Payment.self) } } @@ -170,18 +169,17 @@ public final class Payments: PayPalController { /// - Returns: The payment model that was executed, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func execute(payment id: String, with executor: Payment.Executor, request: String? = nil, partner: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) + return self.client { client in var headers: HTTPHeaders = [:] if let request = request { - headers.add(name: "PayPal-Request-Id", value: request) + headers.add(name: .paypalRequest, value: request) } if let partner = partner { - headers.add(name: "PayPal-Partner-Attribution-Id", value: partner) + headers.add(name: .paypalAttribution, value: partner) } - return try client.post(self.path(for: .payment) + id + "/execute", headers: headers, body: executor, as: Payment.self) + return client.post(self.path(for: .payment) + id + "/execute", headers: headers, body: executor, as: Payment.self) } } @@ -196,9 +194,8 @@ public final class Payments: PayPalController { /// - Returns: The sale object for the ID passed in, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(sale id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .sale) + id, as: RelatedResource.Sale.self) + return self.client { client in + return client.get(self.path(for: .sale) + id, as: RelatedResource.Sale.self) } } @@ -215,11 +212,10 @@ public final class Payments: PayPalController { /// - Returns: The details of the refund, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func refund(sale id: String, with refund: Payment.Refund, request: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - let headers: HTTPHeaders = request == nil ? [:] : ["PayPal-Request-Id": request!] + return self.client { client in + let headers: HTTPHeaders = request == nil ? [:] : [HTTPHeaderName.paypalRequest.description: request!] - return try client.post(self.path(for: .sale) + id + "/refund", headers: headers, body: refund, as: Payment.RefundResult.self) + return client.post(self.path(for: .sale) + id + "/refund", headers: headers, body: refund, as: Payment.RefundResult.self) } } @@ -234,9 +230,8 @@ public final class Payments: PayPalController { /// - Returns: The authorization for the ID passed in, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(authorization id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .authorization) + id, as: RelatedResource.Authorization.self) + return self.client { client in + return client.get(self.path(for: .authorization) + id, as: RelatedResource.Authorization.self) } } @@ -251,9 +246,8 @@ public final class Payments: PayPalController { /// - Returns: The captured authorization, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func capture(authorization id: String, with capture: RelatedResource.Capture) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(for: .authorization) + id + "/capture", body: capture, as: RelatedResource.Authorization.self) + return self.client { client in + return client.post(self.path(for: .authorization) + id + "/capture", body: capture, as: RelatedResource.Authorization.self) } } @@ -275,9 +269,8 @@ public final class Payments: PayPalController { /// - Returns: The re-authorized authorization, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func reauthorize(authorization id: String, with authorization: RelatedResource.Authorization) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(for: .authorization) + id + "/reauthorize", body: authorization, as: RelatedResource.Authorization.self) + return self.client { client in + return client.post(self.path(for: .authorization) + id + "/reauthorize", body: authorization, as: RelatedResource.Authorization.self) } } @@ -292,11 +285,10 @@ public final class Payments: PayPalController { /// - Returns: The voided authorization, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func void(authorization id: String, request: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - let headers: HTTPHeaders = request == nil ? [:] : ["PayPal-Request-Id": request!] + return self.client { client in + let headers: HTTPHeaders = request == nil ? [:] : [HTTPHeaderName.paypalRequest.description: request!] - return try client.post(self.path(for: .authorization) + id + "/void", headers: headers, as: RelatedResource.Authorization.self) + return client.post(self.path(for: .authorization) + id + "/void", headers: headers, as: RelatedResource.Authorization.self) } } @@ -311,9 +303,8 @@ public final class Payments: PayPalController { /// - Returns: The order details for the ID, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(order id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .orders) + id, as: RelatedResource.Sale.self) + return self.client { client in + return client.get(self.path(for: .orders) + id, as: RelatedResource.Sale.self) } } @@ -330,9 +321,8 @@ public final class Payments: PayPalController { /// - Returns:The authorized order, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func authorize(order id: String, with authorization: RelatedResource.Authorization) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(for: .orders) + id + "/authorize", body: authorization, as: RelatedResource.Order.self) + return self.client { client in + return client.post(self.path(for: .orders) + id + "/authorize", body: authorization, as: RelatedResource.Order.self) } } @@ -348,9 +338,8 @@ public final class Payments: PayPalController { /// - Returns: The captured order, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func capture(order id: String, with capture: RelatedResource.Capture) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.post(self.path(for: .orders) + id + "/capture", body: capture, as: RelatedResource.Order.self) + return self.client { client in + return client.post(self.path(for: .orders) + id + "/capture", body: capture, as: RelatedResource.Order.self) } } @@ -365,11 +354,10 @@ public final class Payments: PayPalController { /// - Returns: The voided order, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func void(order id: String, request: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - let headers: HTTPHeaders = request == nil ? [:] : ["PayPal-Request-Id": request!] + return self.client { client in + let headers: HTTPHeaders = request == nil ? [:] : [HTTPHeaderName.paypalRequest.description: request!] - return try client.post(self.path(for: .orders) + id + "/do-void", headers: headers, as: RelatedResource.Order.self) + return client.post(self.path(for: .orders) + id + "/do-void", headers: headers, as: RelatedResource.Order.self) } } @@ -384,9 +372,8 @@ public final class Payments: PayPalController { /// - Returns: The captured transaction, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(captured id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .capture) + id, as: RelatedResource.Capture.self) + return self.client { client in + return client.get(self.path(for: .capture) + id, as: RelatedResource.Capture.self) } } @@ -402,11 +389,10 @@ public final class Payments: PayPalController { /// - Returns: The refunded capture transaction, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func refund(captured id: String, with refund: Payment.Refund, request: String? = nil) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - let headers: HTTPHeaders = request == nil ? [:] : ["PayPal-Request-Id": request!] + return self.client { client in + let headers: HTTPHeaders = request == nil ? [:] : [HTTPHeaderName.paypalRequest.description: request!] - return try client.post(self.path(for: .capture) + id + "/refund", headers: headers, body: refund, as: RelatedResource.Capture.self) + return client.post(self.path(for: .capture) + id + "/refund", headers: headers, body: refund, as: RelatedResource.Capture.self) } } @@ -421,16 +407,15 @@ public final class Payments: PayPalController { /// - Returns: The refund details, wrapped in a future. If PayPal returns an error response, /// it will get converted to a Swift error and the future will wrap that instead. public func get(refund id: String) -> Future { - return Future.flatMap(on: self.container) { () -> Future in - let client = try self.container.make(PayPalClient.self) - return try client.get(self.path(for: .refund) + id, as: RelatedResource.Refund.self) + return self.client { client in + return client.get(self.path(for: .refund) + id, as: RelatedResource.Refund.self) } } // MARK: - Internal Helpers - internal func path(for resource: Resource)throws -> String { - return try self.path() + resource.rawValue + "/" + internal func path(for resource: Resource) -> String { + return self.path + resource.rawValue + "/" } internal enum Resource: String { diff --git a/Sources/PayPal/API/Controllers/Templates.swift b/Sources/PayPal/API/Controllers/Templates.swift index f7d4062d..6ed5f2cd 100644 --- a/Sources/PayPal/API/Controllers/Templates.swift +++ b/Sources/PayPal/API/Controllers/Templates.swift @@ -16,10 +16,14 @@ public final class Templates: PayPalController { /// See `PayPalController.resource` for more information. public let resource: String + /// See `PayPalController.version`. + public let version: Version + /// See `PayPalController.init(container:)`. public init(container: Container) { self.container = container self.resource = "invoicing/templates" + self.version = try container.make(Configuration.self).version || .v1 } @@ -35,9 +39,8 @@ public final class Templates: PayPalController { /// - Returns: The saved template object wrapped in a future. If an error response was sent back instead, /// it gets converted to a Swift error and the future wraps that instead. public func create(template: Template) -> Future